Appearance
Python SDK
bash
pip install ovrinRequires 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| Status | Exception |
|---|---|
| 401 | AuthenticationError |
| 402 | QuotaError |
| 404 | NotFoundError |
| other | ApiError (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 launchPayments
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 pythonIt 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.