Metadata-Version: 2.5
Name: vb-os
Version: 0.1.0
Summary: Python SDK for the VB-OS Verification Cloud Platform
Project-URL: Homepage, https://vb-os.org
Project-URL: Documentation, https://docs.vb-os.org
Project-URL: Repository, https://github.com/VB-OS/vb-os-python-sdk
Author-email: "MNC Labs, Inc." <engineering@vb-os.org>
Maintainer-email: "Asaad N. Riaz" <asaad@vb-os.org>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1.0.0,>=0.27.0
Requires-Dist: pydantic<3.0.0,>=2.0.0
Provides-Extra: cli
Requires-Dist: click<9.0.0,>=8.1.0; extra == 'cli'
Requires-Dist: cryptography<45.0.0,>=43.0.0; extra == 'cli'
Requires-Dist: keyring<26.0.0,>=25.0.0; extra == 'cli'
Requires-Dist: tomli-w<2.0.0,>=1.0.0; extra == 'cli'
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: respx>=0.22.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# VB-OS Python SDK

Python SDK for the VB-OS Verification Cloud Platform.

## Installation

```bash
pip install vb-os
```

## Quick Start

```python
from vbos import VBOSClient

with VBOSClient(api_key="your-api-key") as client:
    result = client.verify(
        workload={"amount": 5000, "currency": "USD"},
        boundary_ref="B_FIN_PAYMENT",
    )
    print(result.decision)  # ASSERT or DEFER
```

### Async Usage

```python
from vbos import AsyncVBOSClient

async with AsyncVBOSClient(api_key="your-api-key") as client:
    result = await client.verify(
        workload={"amount": 5000, "currency": "USD"},
        boundary_ref="B_FIN_PAYMENT",
    )
    print(result.decision)
```

## Configuration

```python
client = VBOSClient(
    api_key="your-api-key",
    base_url="https://api.vb-os.org",  # default
    max_retries=3,                     # default; 5xx only
    timeout=30.0,                      # seconds
)
```

## Resource Namespaces

All 27 resource groups are available as namespaced sub-clients on both
`VBOSClient` (sync) and `AsyncVBOSClient` (async).

### Verification

```python
# Single verification
result = client.verify(workload={"amount": 5000}, boundary_ref="B_FIN")

# Batch verification
results = client.verify_batch(
    workloads=[{"amount": 1000}, {"amount": 2000}],
    boundary_ref="B_FIN",
)

# Dry-run validation (no record created)
validation = client.validate(
    workload={"amount": 5000},
    boundary_ref="B_FIN",
)

# Trigger certification run
run = client.certify(project_id="proj-id", scope="full")
```

### Evaluations

```python
# List evaluations
page = client.evaluations.list("project-id", limit=50)

# Get evaluation detail
detail = client.evaluations.get("project-id", "eval-id")

# Replay an evaluation
replay = client.evaluations.replay("project-id", "eval-id")

# Export evaluations
export = client.evaluations.export("project-id", format="csv")

# Share an evaluation
share = client.evaluations.share("project-id", "eval-id")

# Retrieve a shared evaluation by token
shared = client.evaluations.get_shared("share-token")
```

### Boundaries

```python
boundaries = client.boundaries.list("project-id")
boundary = client.boundaries.create(
    "project-id",
    boundary_ref="B_KYC_CHECK",
    display_name="KYC Check",
)
boundary = client.boundaries.get("project-id", "B_KYC_CHECK")
client.boundaries.update_draft(
    "project-id", "B_KYC_CHECK",
    dsl_source="require_evidence: license_number",
)
client.boundaries.submit("project-id", "B_KYC_CHECK")
versions = client.boundaries.versions("project-id", "B_KYC_CHECK")
version = client.boundaries.get_version("project-id", "B_KYC_CHECK", "v1")
client.boundaries.approve("project-id", "B_KYC_CHECK", "v1")
client.boundaries.reject("project-id", "B_KYC_CHECK", "v1")
diff = client.boundaries.diff("project-id", "B_KYC_CHECK", "v1", "v2")
```

### Deployments

```python
deployments = client.deployments.list("project-id", "env-id")
deployment = client.deployments.create("project-id", "env-id", version_id="v1")
active = client.deployments.active("project-id", "env-id")
client.deployments.approve("project-id", "env-id", "deploy-id")
client.deployments.reject("project-id", "env-id", "deploy-id")
client.deployments.promote("project-id", "env-id", "deploy-id")
client.deployments.rollback("project-id", "env-id", "deploy-id")
```

### Certifications

```python
runs = client.certifications.list("project-id")
run = client.certifications.get("project-id", "run-id")
report = client.certifications.get_report("project-id", "run-id")

# Poll until terminal status (COMPLETED/FAILED/CANCELLED)
result = client.certifications.wait(
    "project-id", "run-id",
    poll_interval_seconds=2.0,
    max_attempts=150,
)
```

### Certification Models

```python
models = client.certification_models.list("project-id")
model = client.certification_models.create("project-id", name="Model A")
version = client.certification_models.create_version(
    "project-id", "model-id",
)
```

### Projects

```python
projects = client.projects.list()
project = client.projects.create(name="My Project", slug="my-project")
project = client.projects.get("project-id")
client.projects.update("project-id", name="Renamed")
client.projects.archive("project-id")
client.projects.delete("project-id")
members = client.projects.list_members("project-id")
client.projects.add_member("project-id", user_id="user-id", role="editor")
client.projects.remove_member("project-id", "user-id")
client.projects.update_member("project-id", "user-id", role="viewer")
```

### Environments

```python
envs = client.environments.list("project-id")
env = client.environments.create("project-id", name="staging")
env = client.environments.get("project-id", "env-id")
client.environments.update("project-id", "env-id", name="production")
client.environments.deactivate("project-id", "env-id")
client.environments.reactivate("project-id", "env-id")
```

### Templates

```python
templates = client.templates.list()
template = client.templates.get("template-id")
fork = client.templates.fork("template-id", project_id="proj-id")
```

### Organization

```python
org = client.org.get()
client.org.update(display_name="My Org")
settings = client.org.get_settings()
client.org.update_settings(default_project="proj-id")
policy = client.org.get_ai_policy()
client.org.update_ai_policy(allowed_models=["gpt-4"])
client.org.transfer_ownership(new_owner_id="user-id")
client.org.accept_transfer("transfer-id")
client.org.cancel_transfer("transfer-id")
transfer = client.org.get_transfer()
```

### Members

```python
members = client.members.list()
client.members.invite(email="user@example.com", role="member")
client.members.set_role("user-id", role="admin")
client.members.remove("user-id")
client.members.suspend("user-id")
client.members.reactivate("user-id")
client.members.revoke_invitation("invitation-id")
```

### API Keys

```python
keys = client.keys.list()
created = client.keys.create(name="CI Key", scopes=["verify"])
key = client.keys.get("key-id")
client.keys.rotate("key-id")
client.keys.revoke("key-id")
client.keys.disable("key-id")
client.keys.enable("key-id")
```

### Service Accounts

```python
accounts = client.service_accounts.list()
account = client.service_accounts.create(name="deploy-bot")
client.service_accounts.update("sa-id", name="deploy-bot-v2")
client.service_accounts.disable("sa-id")
client.service_accounts.enable("sa-id")
```

### Webhooks

```python
hooks = client.webhooks.list("project-id")
hook = client.webhooks.create("project-id", url="https://...")
client.webhooks.update("project-id", "hook-id", url="https://new")
client.webhooks.delete("project-id", "hook-id")
client.webhooks.rotate_secret("project-id", "hook-id")
deliveries = client.webhooks.deliveries("project-id", "hook-id")
org_hooks = client.webhooks.list_org()
client.webhooks.create_org(url="https://org-level")
```

### Analytics

```python
rate = client.analytics.assertion_rate("project-id")
deferral = client.analytics.deferral_rate("project-id")
summary = client.analytics.evaluations("project-id")
failures = client.analytics.failure_reasons("project-id")
latency = client.analytics.latency("project-id")
```

### Audit Log

```python
logs = client.audit_log.list()
job = client.audit_log.export(start="2025-01-01", end="2025-02-01")
status = client.audit_log.export_status("job-id")
```

### Billing

```python
usage = client.billing.usage()
subscription = client.billing.subscription()
invoices = client.billing.invoices()
```

### Flows

```python
flow = client.flows.create("project-id", name="Onboarding")
flows = client.flows.list("project-id")
flow = client.flows.get("project-id", "flow-id")
client.flows.update("project-id", "flow-id", name="Updated")
client.flows.delete("project-id", "flow-id")
export = client.flows.export("project-id", "flow-id")
client.flows.import_flow("project-id", definition={...})
client.flows.from_template("project-id", template_id="tmpl-id")
v = client.flows.create_version("project-id", "flow-id")
versions = client.flows.list_versions("project-id", "flow-id")
v = client.flows.get_version("project-id", "flow-id", "v1")
client.flows.update_version("project-id", "flow-id", "v1", name="v1-fix")
client.flows.delete_version("project-id", "flow-id", "v1")
client.flows.approve_version("project-id", "flow-id", "v1")
client.flows.deploy("project-id", "flow-id", env_id="env-id")
client.flows.suspend("project-id", "flow-id")
dry = client.flows.dry_run("project-id", "flow-id", workload={...})
execs = client.flows.list_executions("project-id", "flow-id")
recon = client.flows.reconstruct_execution(
    "project-id", "flow-id", "exec-id",
)
```

### Flow Templates

```python
templates = client.flow_templates.list()
template = client.flow_templates.get("template-id")
```

### Alert Rules

```python
rule = client.alert_rules.create("project-id", name="High Defer")
rules = client.alert_rules.list("project-id")
rule = client.alert_rules.get("project-id", "rule-id")
client.alert_rules.update("project-id", "rule-id", name="Updated")
client.alert_rules.delete("project-id", "rule-id")
```

### Connectors

```python
connector = client.connectors.create("project-id", provider="npi")
connectors = client.connectors.list("project-id")
connector = client.connectors.get("project-id", "conn-id")
client.connectors.update("project-id", "conn-id", name="Renamed")
client.connectors.delete("project-id", "conn-id")
test = client.connectors.test("project-id", "conn-id")
gather = client.connectors.gather("project-id", "conn-id")
analytics = client.connectors.analytics("project-id", "conn-id")
resources = client.connectors.resources("project-id", "conn-id")
schema = client.connectors.schema("project-id", "conn-id")
schedule = client.connectors.get_schedule("project-id", "conn-id")
client.connectors.set_schedule("project-id", "conn-id", cron="0 * * * *")
gathers = client.connectors.list_gathers("project-id", "conn-id")
```

### Connector Providers

```python
providers = client.connector_providers.list()
schema = client.connector_providers.schema("npi")
```

### Named Sets

```python
ns = client.named_sets.create("project-id", name="Exclusions")
sets = client.named_sets.list("project-id")
ns = client.named_sets.get("project-id", "set-id")
client.named_sets.update("project-id", "set-id", name="Updated")
client.named_sets.delete("project-id", "set-id")
usage = client.named_sets.usage("project-id", "set-id")
```

### Governed Workspaces

```python
gw = client.governed_workspaces.create("project-id", name="Prod")
gws = client.governed_workspaces.list("project-id")
gw = client.governed_workspaces.get("project-id", "gw-id")
v = client.governed_workspaces.create_version("project-id", "gw-id")
v = client.governed_workspaces.get_version("project-id", "gw-id", "v1")
client.governed_workspaces.submit("project-id", "gw-id", "v1")
client.governed_workspaces.approve("project-id", "gw-id", "v1")
client.governed_workspaces.deploy("project-id", "gw-id", "v1")
client.governed_workspaces.archive("project-id", "gw-id")
inst = client.governed_workspaces.create_instance(
    "project-id", "gw-id",
)
client.governed_workspaces.submit_instance(
    "project-id", "gw-id", "inst-id",
)
inst = client.governed_workspaces.get_instance(
    "project-id", "gw-id", "inst-id",
)
```

### Notifications

```python
notifications = client.notifications.list()
client.notifications.read("notification-id")
client.notifications.unread("notification-id")
```

### Account

```python
client.account.delete()
client.account.cancel_delete()
status = client.account.deletion_status()
export = client.account.export()
latest = client.account.export_latest()
status = client.account.export_status("export-id")
download = client.account.export_download("export-id")
```

### Workspaces

```python
workspaces = client.workspaces.list()
ws = client.workspaces.create(name="Engineering")
ws = client.workspaces.get("ws-id")
client.workspaces.update("ws-id", name="Renamed")
client.workspaces.archive("ws-id")
client.workspaces.delete("ws-id")
members = client.workspaces.list_members("ws-id")
client.workspaces.add_member("ws-id", user_id="user-id")
client.workspaces.remove_member("ws-id", "user-id")
```

### Users

```python
me = client.users.me()
orgs = client.users.organizations()
```

## Error Handling

```python
from vbos import (
    VBOSError,
    VBOSAuthenticationError,
    VBOSAuthorizationError,
    VBOSNotFoundError,
    VBOSRateLimitError,
    VBOSServerError,
    VBOSValidationError,
)

try:
    result = client.verify(workload={"amount": 5000})
except VBOSRateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
except VBOSAuthenticationError:
    print("Invalid API key")
except VBOSNotFoundError:
    print("Resource not found")
except VBOSServerError:
    print("Server error (retried automatically)")
except VBOSError as e:
    print(f"[{e.status_code}] {e.error_code}: {e.message}")
```

## Retry Behavior

- **5xx responses** are retried with full-jitter exponential backoff
  (up to `max_retries`, default 3).
- **429 (rate limited)** raises `VBOSRateLimitError` immediately
  (no automatic retry). The `retry_after` attribute contains the
  server-suggested wait time.
- All other errors raise immediately without retry.

## Development

```bash
pip install -e ".[dev]"
python -m pytest tests/ -v
python -m ruff check vbos/ tests/
```
