# Python client

```bash
pip install envpass-cli    # or: uv add envpass-cli
```

The package supports Python 3.9+ and has no dependencies. Import it as `envpass`.

## Load values into os.environ

```python
from envpass import load_env

load_env("prod")
```

`load_env` reads the token from `ENVPASS_TOKEN` or the CLI login and scope from its arguments, `ENVPASS_*` variables or `.envpass.json`. Existing variables are kept unless you pass `override=True`. It returns the loaded values as a dict.

With a user login, pass the workspace and project too, unless `.envpass.json` already has them:

```python
load_env("dev", workspace="acme", project="shop")
```

## Client

```python
from envpass import Envpass

client = Envpass(token="ep_live_...")

entries = client.resolve({"environment": "prod"})
# [{"key": "DATABASE_URL", "value": "postgres://...", "source": "shared"}, ...]

text = client.resolve_text({"environment": "prod"}, "dotenv")
me = client.me()
```

`source` is `"shared"` for the team value and `"personal"` for your own override, which only applies with a user login on environments that allow it.

`Envpass` also takes `user_agent` and `timeout` (seconds, default 30). The server URL is its first argument, then `ENVPASS_URL`, then `https://envpass.dev`. Without `token`, it uses `ENVPASS_TOKEN` or the saved CLI login.

Any REST endpoint is available through `request`:

```python
workspaces = client.request("GET", "/api/v1/workspaces")["workspaces"]
client.request(
    "PUT",
    f"/api/v1/workspaces/{workspace_id}/projects/{project_id}/secrets",
    body={"environmentId": env_id, "entries": [{"key": "FEATURE_FLAG", "value": "on"}]},
)
```

## Webhooks and syncs

These methods need a user login. With a service token they raise `EnvpassError` with code `forbidden`. Each takes an optional `scope`, resolved like `load_env`: `{"workspace": ...}` for webhooks, plus `"project"` for syncs.

```python
from envpass import Envpass

client = Envpass()
scope = {"workspace": "acme", "project": "shop"}

created = client.create_webhook(
    "https://example.com/hooks/envpass",
    events=["secrets.changed"],
    environments=["prod"],
    scope=scope,
)
secret = created["secret"]  # store it now: it is only returned once

result = client.test_webhook(created["webhook"]["id"], scope=scope)
# {"ok": True, "responseStatus": 200, "durationMs": 143, "error": None}

for sync in client.list_syncs(scope):
    if sync["status"] == "error":
        client.run_sync(sync["id"], scope)
```

| Method | Does |
|---|---|
| `list_webhooks(scope)` | The workspace's webhooks |
| `create_webhook(url, *, events, environments, projects, fmt, description, scope)` | `environments` and `projects` are slugs. Returns `webhook` and `secret`. |
| `delete_webhook(id, scope)` | Delete a webhook |
| `test_webhook(id, scope)` | Send a test event and return the result |
| `list_webhook_deliveries(id, limit, before, scope)` | Recent deliveries, newest first |
| `list_connections(scope)` | Vercel and GitHub connections |
| `list_syncs(scope)` | The project's syncs |
| `run_sync(id, scope)` | Queue a sync now |
| `set_sync_enabled(id, enabled, scope)` | Pause or resume a sync |

See [Webhooks](/docs/webhooks) for payloads and signature checks, and [Syncs](/docs/syncs) for how syncs behave.

## Django and FastAPI

Call `load_env` before settings are read:

```python
# settings.py or main.py
from envpass import load_env

load_env()  # uses .envpass.json and ENVPASS_TOKEN
```

## Errors

Methods raise `envpass.EnvpassError` with `status` and `code`:

```python
from envpass import EnvpassError

try:
    client.resolve({"environment": "prod"})
except EnvpassError as error:
    if error.code == "forbidden":
        print("This token can't read prod")
```
