Skip to content

Python SDK

bash
pip install ovrin

Requires Python 3.10+.

Client

python
import ovrin

client = ovrin.Client()                       # api key from OVRIN_API_KEY
client = ovrin.Client(api_key="ovrin_...")    # or explicit
client = ovrin.Client(base_url="https://api.ovrin.app")

with ovrin.Client() as client:                # context manager closes connections
    ...

Errors raise a typed hierarchy carrying the API's stable machine-readable code alongside the message:

python
from ovrin import ApiError, AuthenticationError, NotFoundError, OvrinError, QuotaError
StatusException
401AuthenticationError
402QuotaError
404NotFoundError
otherApiError (base: OvrinError)

Sandboxes

python
sandbox = client.sandboxes.create(
    template="claude-code",
    timeout=3600,                      # seconds, minimum 60
    env={"ANTHROPIC_API_KEY": key},
    secrets=[{"name": "github-prod", "auth_type": "bearer",
              "hosts": ["api.github.com"]}],
    payments=True,                     # inject the agent-payments key
    idempotency_key="run-42",          # safe retries
)

result = sandbox.run('claude "fix the failing test"')
print(result.stdout, result.stderr, result.error)

for event in client.sandboxes.stream(sandbox.id, "npm test"):
    if event["type"] == "stdout":
        print(event["text"], end="")

sandbox.pause()
sandbox.resume()
sandbox.renew(expires_at=datetime.now() + timedelta(hours=24))
metadata = {"ticket": "JIRA-1"}; client.sandboxes.set_metadata(sandbox.id, metadata)
sandbox.kill()

client.sandboxes.list()
client.sandboxes.get(sandbox.id)

Files

Binary-safe by construction — text travels as UTF-8, bytes as base64:

python
sandbox.files.write("/workspace/run.py", "print('hi')")
sandbox.files.write("/workspace/blob.bin", b"\x00\x01\x02")   # bytes -> base64

text = sandbox.files.read("/workspace/run.py")
data = sandbox.files.read_bytes("/workspace/blob.bin")         # -> bytes

sandbox.files.list("/workspace", depth=1)
info = sandbox.files.stat("/workspace/run.py")
matches = sandbox.files.search("/workspace", "def train_")
sandbox.files.move("/workspace/a.py", "/workspace/b.py")
sandbox.files.mkdir("/workspace/pkg")
sandbox.files.delete("/workspace/b.py")

Stateful code

On a code-interpreter sandbox, variables persist across calls within a context:

python
result = sandbox.run_code("x = 41")
result = sandbox.run_code("print(x + 1)")        # 42 — same context

ctx = sandbox.create_context(language="python")  # explicit contexts
contexts = sandbox.contexts()
sandbox.delete_context(ctx["context_id"])

Endpoints

Public HTTP URL for a port inside the sandbox:

python
info = client.sandboxes.endpoint(sandbox.id, 8080)
print(info["url"])

HTTP today; WebSockets need the ingress gateway (roadmap).

Snapshots

python
snap = client.sandboxes.snapshot(sandbox.id, name="golden")
restored = client.sandboxes.restore(snapshot_id=snap["snapshot_id"],
                                    template="python")
client.snapshots.list(); client.snapshots.delete(snapshot_id)

Memory

See Persistent Memory for scoping semantics.

python
client.memory.add("prefers pytest over unittest")
hits = client.memory.search("test framework", limit=10)
all_of_them = client.memory.list()
client.memory.delete(memory_id)

Secrets

python
client.secrets.create("github-prod", "ghp_...")
client.secrets.list()      # names only — values are never returned
client.secrets.delete("github-prod")

Keys

Scopes and expiry keep blast radius small; rotation swaps atomically. See API Keys & Scopes.

python
client.keys.list()
raw = client.keys.create("ci", scope="sandboxes",
                         expires_at="2026-12-01T00:00:00Z")
fresh = client.keys.rotate(key_id)
client.keys.delete(key_id)

Usage & templates

python
usage = client.usage.get()          # totals for the account
templates = client.templates.list() # what this account can launch

Payments

BYO Stripe restricted key; see Agent Payments.

python
client.payments.set_credentials("rk_live_...")
client.payments.credentials_status()
client.payments.clear_credentials()

client.payments.agent_key_status()
raw = client.payments.create_agent_key()   # the persistent payments-scoped key

customer = client.payments.create_customer("Acme", email="billing@acme.com")
client.payments.list_customers(limit=20)
invoice = client.payments.create_invoice(customer["id"])
link = client.payments.create_payment_link("price_1", quantity=1)

Benchmarking

The package installs an ovrin-bench command that measures sandbox creation latency against your deployment.

bash
ovrin-bench -n 10 --template python

It reports p50, p95 and mean creation time, killing each sandbox as soon as it is created. Because those are real sandboxes your account is billed for, it asks for confirmation first; pass --yes to skip the prompt in a script.

WARNING

ovrin-bench creates billable sandboxes. Start with a small -n.