> ## 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.

# Migrando para a v5

> O que mudou entre o squarecloud-api v4 e v5: um cliente síncrono com uma fachada await, dicts simples em vez de dataclasses, métodos agrupados por recurso, uma única classe de exceção. Uma tabela método a método.

A v5 é uma reescrita. O SDK agora é síncrono por padrão (com uma fachada `await`), não tem nenhuma dependência, agrupa os métodos por recurso, retorna dicts simples (`TypedDict`) e lança um único tipo de exceção. Ele cobre todas as 67 operações da API da Square Cloud.

## Visão geral

| v4                                                                                                     | v5                                                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `await client.x(...)`, apenas assíncrono                                                               | `client.group.x(...)`, ou `await async_client.group.x(...)`                                                                                                                |
| Dataclasses congeladas (`status.ram`)                                                                  | `TypedDict`, um dict simples (`status['ram']`); campos desconhecidos são mantidos em vez de lançar `TypeError`                                                             |
| Objetos `Application` (`app.start()`, `app.cache`)                                                     | Dados simples mais ids: `client.apps.start(app_id)`. Não há cache                                                                                                          |
| \~25 classes de exceção (`NotFoundError`, `TooManyRequests`, `FewMemory`, ...)                         | `SquareCloudAPIError` com `.status`, `.code`, `.message`, `.method`, `.path` (`'/v2/...'`), `.cause`                                                                       |
| `squarecloud.File(path)`                                                                               | Passe um caminho, `bytes` ou um objeto de arquivo binário diretamente                                                                                                      |
| Argumentos opcionais por posição                                                                       | Modificadores opcionais são keyword-only (`status(id, raw=True)`, `commit(id, file, path=...)`, `databases.create(name, type=, version=, memory=)`)                        |
| Listeners de requisição (`@client.on_request`), listeners de captura, `avoid_listener`, `update_cache` | Removidos. Use o [logger](/pt-br/sdks/py/client#registro-de-logs) `squarecloud` (DEBUG) ou um [`transport=`](/pt-br/sdks/py/client#transporte-personalizado) personalizado |
| Dependências `aiohttp` e `typing-extensions`                                                           | Nenhuma                                                                                                                                                                    |
| Python `>=3.13,<3.15`                                                                                  | Python `>=3.11`, sem limite superior                                                                                                                                       |

## Construção e opções

| v4                                                                             | v5                                                                                                                                                             |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `squarecloud.Client(api_key, log_level=...)`                                   | `SquareCloud(api_key, *, base_url=BASE_URL, timeout=30.0, max_retries=2, transport=None, user_agent=...)`, ou `AsyncSquareCloud(...)` com os mesmos argumentos |
| `log_level=` e um handler colorido anexado na importação                       | `logging.getLogger('squarecloud')` com um `NullHandler`; configure-o você mesmo                                                                                |
| Padrões do `aiohttp` (5 min por requisição; 90 s entre leituras do tempo real) | `timeout` em segundos por operação de socket, com um mínimo de 120 s para chamadas mantidas abertas e de IA; `timeout <= 0` desativa todos os timeouts         |
| Sem novas tentativas                                                           | `max_retries` (2) apenas para as falhas seguras; um 429 nunca é repetido                                                                                       |
| `User-Agent` fixo no código                                                    | `user_agent=` substitui o header (padrão `squarecloud-sdk-py/<version>`)                                                                                       |
| Uma nova sessão por requisição                                                 | `close()` ou `with` / `async with` fecha as conexões keep-alive do pool                                                                                        |

## Método a método

| antigo (v4 `Client`)                                                                              | novo (v5 `SquareCloud`)                                                              | observações                                                                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user()`                                                                                          | `account.me()['user']`                                                               | `me()` também retorna `applications` e `databases`                                                                                                                                                                                                                                                             |
| `all_apps()`                                                                                      | `account.me()['applications']`                                                       |                                                                                                                                                                                                                                                                                                                |
| `app(app_id)`                                                                                     | `apps.get(app_id)`                                                                   | Agora usa `GET /apps/{id}`: funciona com ids de workspace `'<appId>-<workspaceId>'`                                                                                                                                                                                                                            |
| `user_snapshots(scope)`                                                                           | `account.snapshots(*, scope=None)`                                                   | `scope` é keyword-only. Os itens trazem o `version_id` e a `url` assinada da API                                                                                                                                                                                                                               |
| `service_status()`                                                                                | `service.status()`                                                                   |                                                                                                                                                                                                                                                                                                                |
| `upload_app(File(path))`                                                                          | `apps.create(path)`                                                                  | Transmite do disco; retorna `AppCreated` (`domain` é o host completo de um site; não há `subdomain`)                                                                                                                                                                                                           |
| `delete_app(id)`                                                                                  | `apps.delete(id)`                                                                    | Retorna `None`                                                                                                                                                                                                                                                                                                 |
| `all_apps_status()`                                                                               | `apps.status_all(*, workspace_id=None)`                                              | Aplicações paradas não são mais descartadas                                                                                                                                                                                                                                                                    |
| `app_status(id)`                                                                                  | `apps.status(id, *, raw=False)`                                                      | `raw=True` (keyword-only) retorna números                                                                                                                                                                                                                                                                      |
| `start_app` / `stop_app` / `restart_app`                                                          | `apps.start` / `apps.stop` / `apps.restart`                                          | Retornam `None`                                                                                                                                                                                                                                                                                                |
| `get_logs(id)`                                                                                    | `apps.logs(id)`                                                                      | Retorna a `str`                                                                                                                                                                                                                                                                                                |
| `app_metrics(id)`                                                                                 | `apps.metrics(id)`                                                                   |                                                                                                                                                                                                                                                                                                                |
| `realtime(id)` (gerador assíncrono de cada linha `data:`, decodificada como JSON quando possível) | `apps.realtime(id)`                                                                  | Iterador de `{'event', 'data', 'id'}` com o texto bruto de `data`, além de `stream`/`line` nos logs e o `status` mesclado nos eventos de status. Reconecta sozinho (veja Mudanças de comportamento); o stream não tem timeout de leitura (a v4 desistia após 90 s sem dados), então interrompa-o com `close()` |
| `all_domains()`                                                                                   | `apps.domains()`                                                                     |                                                                                                                                                                                                                                                                                                                |
| `load_balancers()`                                                                                | `apps.load_balancers()`                                                              |                                                                                                                                                                                                                                                                                                                |
| `commit(id, File(path))`                                                                          | `apps.commit(id, file, *, path=None, filename=None)`                                 | `path` keyword-only = diretório de destino; `filename` nomeia um arquivo que não é zip (`bytes` usam `commit.zip` por padrão)                                                                                                                                                                                  |
| `github_integration(id, access_token)`                                                            | `apps.deploys.set_webhook(id, access_token)`                                         |                                                                                                                                                                                                                                                                                                                |
| `last_deploys(id)`                                                                                | `apps.deploys.list(id)`                                                              | Os eventos incluem `source`, `branch`, `files`; um deploy que falhou termina com `state='error'` mais `code` e `message`                                                                                                                                                                                       |
| `current_app_integration(id)`                                                                     | `apps.deploys.current(id)`                                                           | Retorna `{'app'?, 'webhook'?}` em vez da string do webhook                                                                                                                                                                                                                                                     |
| `get_app_envs` / `set_app_envs` / `overwrite_app_envs` / `delete_app_envs`                        | `apps.envs.get` / `set` / `replace` / `delete`                                       |                                                                                                                                                                                                                                                                                                                |
| `clear_app_envs(id)`                                                                              | `apps.envs.replace(id, {})`                                                          |                                                                                                                                                                                                                                                                                                                |
| `app_files_list(id, path)`                                                                        | `apps.files.list(id, path=None)`                                                     | As entradas são o `FileEntry` da API (sem `path`/`app_id` calculados). Um diretório inexistente lança 404 `FILE_NOT_FOUND` em vez de retornar `[]`; um bloqueado resulta em 403 `BLOCKED_PATH`                                                                                                                 |
| `read_app_file(id, path)` → `BytesIO`                                                             | `apps.files.read(id, path)` → `bytes`                                                | Obtido codificado em base64 (`?encoding=base64`) e decodificado; acima de 10 MB resulta em 413 `FILE_TOO_LARGE`                                                                                                                                                                                                |
| `create_app_file(id, File(...), path)`                                                            | `apps.files.write(id, path, content)`                                                | Uma `str` é enviada como texto, `bytes` codificados em base64 (seguro para binários); o caminho é enviado literalmente (sem `/` extra); conteúdo vazio (`''` ou `b''`) cria um arquivo vazio                                                                                                                   |
| `move_app_file(id, origin, dest)`                                                                 | `apps.files.move(id, path, to)`                                                      |                                                                                                                                                                                                                                                                                                                |
| `delete_app_file(id, path)`                                                                       | `apps.files.delete(id, path)`                                                        |                                                                                                                                                                                                                                                                                                                |
| `snapshot(id)` → `Snapshot`                                                                       | `apps.snapshots.create(id)`                                                          | `{'pending': True}` em um 202 em vez de lançar erro; depois consulte `list`, nunca crie de novo                                                                                                                                                                                                                |
| `all_app_snapshots(id)`                                                                           | `apps.snapshots.list(id)`                                                            | Os itens trazem o `version_id` e a `url` de download assinada da API, repassados como enviados                                                                                                                                                                                                                 |
| `restore_snapshot('app', id, snapshot_id, version_id)`                                            | `apps.snapshots.restore(id, name, version_id)`                                       | `name` e `version_id` de um item de `list`                                                                                                                                                                                                                                                                     |
| `restore_snapshot('database', id, ...)`                                                           | `databases.snapshots.restore(id, name, version_id)`                                  | `name` e `version_id` de um item de `list`                                                                                                                                                                                                                                                                     |
| `Snapshot.download(path)`                                                                         | `client.download_snapshot(url, dest)`                                                | Transmite o próprio zip (a v4 o encapsulava em outro zip)                                                                                                                                                                                                                                                      |
| `domain_analytics(id, start=, end=, ...)`                                                         | `apps.network.analytics(id, start, end, *, country=, ...)`                           | `start`/`end` são exigidos pela API; os filtros são keyword-only                                                                                                                                                                                                                                               |
| `network_errors(id, start, end, include_4xx)` / `network_logs` / `network_performance`            | `apps.network.errors(id, start, end, *, include_4xx=False)` / `logs` / `performance` | `analytics`, `errors` e `performance` retornam `None` para uma janela sem dados                                                                                                                                                                                                                                |
| `dns_records(id)`                                                                                 | `apps.network.dns(id)`                                                               |                                                                                                                                                                                                                                                                                                                |
| `set_custom_domain(id, custom_domain)`                                                            | `apps.network.set_domain(id, domain)`                                                | A v4 nunca enviava o corpo                                                                                                                                                                                                                                                                                     |
| `purge_cache(id)`                                                                                 | `apps.network.purge_cache(id)`                                                       |                                                                                                                                                                                                                                                                                                                |
| `link_github_app(id, repository_name, repository_branch)`                                         | `apps.deploys.link_github_app(id, repository, branch)`                               | Agora funciona com uma chave de API (escopo `apps:deploy`); retorna o `LinkedRepository` (`{id, full_name, branch}`) em vez do dict bruto; 403 `GITHUB_NOT_CONNECTED` sem uma instalação do GitHub App                                                                                                         |
| `unlink_github_app(id)`                                                                           | `apps.deploys.unlink_github_app(id)`                                                 | Retorna `None`; 400 `GIT_NOT_CONFIGURED` quando nada está vinculado                                                                                                                                                                                                                                            |
| `create_database(name, memory, type, version=None)`                                               | `databases.create(name, type=, version=, memory=)`                                   | Keyword-only; `version` é obrigatório (uma versão principal como `'8'` funciona)                                                                                                                                                                                                                               |
| `get_database_info(id)`                                                                           | `databases.get(id)`                                                                  |                                                                                                                                                                                                                                                                                                                |
| `edit_database(id, name, memory)`                                                                 | `databases.update(id, name=, ram=)`                                                  | A v4 enviava `memory`, que a API ignorava                                                                                                                                                                                                                                                                      |
| `delete_database` / `start_database` / `stop_database`                                            | `databases.delete` / `start` / `stop`                                                |                                                                                                                                                                                                                                                                                                                |
| `get_database_status(id)`                                                                         | `databases.status(id, *, raw=False)`                                                 |                                                                                                                                                                                                                                                                                                                |
| `all_databases_status()`                                                                          | `databases.status_all()`                                                             |                                                                                                                                                                                                                                                                                                                |
| `database_metrics(id)`                                                                            | `databases.metrics(id)`                                                              |                                                                                                                                                                                                                                                                                                                |
| `get_database_certificate(id)` → `Certificate`                                                    | `databases.certificate(id)` → `str` em base64                                        | `base64.b64decode(...)` fornece o PEM                                                                                                                                                                                                                                                                          |
| `reset_database_password(id)`                                                                     | `databases.reset_credentials(id, 'password')`                                        | Retorna a nova senha                                                                                                                                                                                                                                                                                           |
| `reset_database_certificate(id)`                                                                  | `databases.reset_credentials(id, 'certificate')`                                     | Retorna `''`                                                                                                                                                                                                                                                                                                   |
| `all_database_snapshots(id)` / `database_snapshot(id)`                                            | `databases.snapshots.list(id)` / `create(id)`                                        | Os itens trazem `version_id` e `url`, como nas aplicações                                                                                                                                                                                                                                                      |
| `create_workspace(name)`                                                                          | `workspaces.create(name)`                                                            | Retorna `{id, name}` em uma única requisição                                                                                                                                                                                                                                                                   |
| `all_workspaces()` / `get_workspace(id)`                                                          | `workspaces.list()` / `workspaces.get(id)`                                           | A v4 reescrevia o `id` de cada aplicação para o composto `'<appId>-<workspaceId>'`; a v5 retorna o id bruto da API, então monte-o você mesmo: `f"{app['id']}-{workspace['id']}"`                                                                                                                               |
| `delete_workspace` / `leave_workspace`                                                            | `workspaces.delete` / `workspaces.leave`                                             |                                                                                                                                                                                                                                                                                                                |
| `add_member_to_workspace(ws, invite_code, permissions)`                                           | `workspaces.members.add(ws, code, group)`                                            |                                                                                                                                                                                                                                                                                                                |
| `modify_member_permissions(ws, user_id, permissions)`                                             | `workspaces.members.update(ws, member_id, group)`                                    |                                                                                                                                                                                                                                                                                                                |
| `remove_member_from_workspace(ws, user_id)`                                                       | `workspaces.members.remove(ws, member_id)`                                           |                                                                                                                                                                                                                                                                                                                |
| `get_invite_code()`                                                                               | `workspaces.members.invite_code()`                                                   |                                                                                                                                                                                                                                                                                                                |
| `add_app_to_workspace` / `remove_app_from_workspace`                                              | `workspaces.apps.add` / `workspaces.apps.remove`                                     |                                                                                                                                                                                                                                                                                                                |
| —                                                                                                 | `ai.chat(request)`                                                                   | Novo; `request` é o corpo no estilo OpenAI (`{'messages': [...], 'model': ...}`)                                                                                                                                                                                                                               |
| `client.api_key`                                                                                  | Removido                                                                             | Mantenha sua própria referência à chave                                                                                                                                                                                                                                                                        |
| `on_request(endpoint)`, `Application.capture(endpoint)`                                           | Removidos                                                                            | Veja a linha dos listeners em [Visão geral](#visão-geral)                                                                                                                                                                                                                                                      |
| `squarecloud.utils.ConfigFile`                                                                    | Removido                                                                             | Escreva o arquivo `squarecloud.app` você mesmo (linhas `KEY=value`)                                                                                                                                                                                                                                            |

Os métodos de `Application` correspondem às mesmas chamadas com o id: `app.logs()` → `client.apps.logs(app.id)`, `app.files_list(path)` → `client.apps.files.list(app.id, path)`, e assim por diante.

## Tipos

As respostas são `TypedDict`s em `squarecloud.types`, com os mesmos nomes dos SDKs de JS e Go: `Account`, `User`, `Plan`, `AppSummary`, `DatabaseSummary`, `App`, `AppCreated`, `StatusListItem`, `RuntimeStats`, `MetricPoint`, `AppDomain`, `LoadBalancers`, `DeployEvent`, `DeployCurrent`, `DeployRepository`, `LinkedRepository`, `EnvVars`, `FileEntry`, `Snapshot`, `SnapshotCreated`, `SnapshotScope`, `AnalyticsFilters`, `NetworkAnalytics`, `NetworkErrors`, `NetworkLog`, `NetworkPerformance`, `DNSRecord`, `Database`, `DatabaseCreated`, `DatabaseType`, `Workspace`, `WorkspaceCreated`, `WorkspaceGroup`, `ServiceStatus`, `ServiceEntry`, `ChatRequest`, `ChatMessage`, `ChatCompletion`, `RealtimeEvent`, `RealtimeStatus`. Eles substituem as dataclasses `data/*` da v4 (`UserData`, `StatusData`, `AppData`, ...). `squarecloud.Response` agora é o protocolo de resposta do transporte (veja [Transporte personalizado](/pt-br/sdks/py/client#transporte-personalizado)); o `Response` da v4 que as mutações retornavam não existe mais, e elas retornam `None`.

## Erros

| v4                                                             | v5                                                                                                                  |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `AuthenticationFailure`                                        | `e.status == 401` (`ACCESS_DENIED`, também para uma chave expirada)                                                 |
| `NotFoundError`, `ApplicationNotFound`                         | `e.status == 404` (`APP_NOT_FOUND`, `WORKSPACE_NOT_FOUND`, ...)                                                     |
| `BadRequestError` e a família `InvalidConfig`                  | `e.status == 400`, verifique `e.code`                                                                               |
| `TooManyRequests`                                              | `e.status == 429` (`RATE_LIMITED`, `KEEP_CALM`)                                                                     |
| `FewMemory` (nunca lançado: a API envia `INSUFFICIENT_MEMORY`) | `e.code == 'INSUFFICIENT_MEMORY'`                                                                                   |
| `InvalidDomain` (`REGEX_VALIDATION`, não é mais enviado)       | `e.code == 'INVALID_DOMAIN'`                                                                                        |
| `RequestError` para 403/503                                    | `e.code` em `MISSING_SCOPE`, `RESOURCE_NOT_ALLOWED`, `BLOCKED_PATH`, `UPLOAD_BUSY`, ...                             |
| Exceções do `aiohttp` vazando                                  | `e.status == 0`, `e.code` em `NETWORK_ERROR`, `TIMEOUT` (exceção original em `e.cause`)                             |
| —                                                              | `e.status == 0` com `FILE_TOO_LARGE` ou `INVALID_ID`: verificações locais, nada foi enviado                         |
| HTML de proxy ou um corpo que não é JSON vazando               | `UNKNOWN_ERROR` com o status real e a mensagem `HTTP <status>` (`Invalid JSON in HTTP <status> response` em um 2xx) |

`str(e)` é `'<METHOD> <path>: HTTP <status> <CODE>: <message>'`, sem `HTTP <status>` quando o status é `0` e sem `: <message>` quando a mensagem está vazia. `e.message` é `''` quando o servidor enviou apenas um código.

## Mudanças de comportamento

* Modificadores opcionais são keyword-only: `account.snapshots(scope=)`, `apps.status_all(workspace_id=)`, `apps.status(id, raw=)`, `databases.status(id, raw=)`, `apps.commit(id, file, path=, filename=)`, `apps.network.errors(..., include_4xx=)`, os filtros de `apps.network.analytics(...)`, `databases.update(id, name=, ram=)` e `databases.create(name, type=, version=, memory=)`. O `path` opcional de `apps.files.list` continua posicional.
* Um corpo 2xx `{"status": "error"}` lança um erro. As recusas de start/stop de aplicações e bancos de dados são 409 apenas com um código (`CONTAINER_ALREADY_STARTED`, `ACTION_FAILED`, ...). Um 202 `SNAPSHOT_PROCESSING` retorna `{'pending': True}` em vez de lançar um erro: consulte `list`, nunca chame `create` novamente.
* Valores opcionais de query não definidos (e `''`) são omitidos em vez de enviados.
* Resultados string nunca são `None`: `reset_credentials(id, 'certificate')` e um webhook removido retornam `''`.
* `apps.files.write` envia uma `str` como texto e `bytes` codificados em base64; conteúdo vazio cria um arquivo vazio; conteúdo acima de 1 MiB é enviado sem timeout. `apps.files.read` sempre pede base64 e retorna os `bytes` decodificados.
* `apps.files.list` de um diretório inexistente lança 404 `FILE_NOT_FOUND`.
* O 503 `DATABASE_UNAVAILABLE` é repetido apenas em `GET`, já que pode ocorrer depois que uma mutação foi aplicada; repetir uma mutação idempotente fica a cargo de quem chama.
* O stream em tempo real produz eventos `{'event', 'data', 'id', ...}`, reabre no máximo 3 vezes seguidas a um ritmo de uma abertura a cada 5,5 s e lança um erro quando uma abertura falha.

## Assíncrono

A v4 era apenas assíncrona. Na v5, `SquareCloud` é síncrono e `AsyncSquareCloud` é a fachada `await`: os mesmos grupos e métodos, cada chamada executada em `asyncio.to_thread`, então o event loop nunca é bloqueado. O stream em tempo real passa a usar `async for` (uma thread de leitura alimenta o loop); feche-o com `async with` ou `close()`.

v4:

```python theme={"system"}
client = squarecloud.Client(key)
status = await client.app_status(app_id)
print(status.ram)
async for data in client.realtime(app_id):
    print(data)
```

v5:

```python theme={"system"}
async with squarecloud.AsyncSquareCloud(key) as client:
    status = await client.apps.status(app_id)
    print(status['ram'])
    async with client.apps.realtime(app_id) as stream:
        async for event in stream:
            print(event['data'])
```
