Files
sand-boxer/docs/payments.md
tegwick 15f031fd65 feat: cloud adapters E2B/Modal and billing export (SAND-WP-0010)
Add credentialed E2B and Modal extensions, burst routing fallback,
fin-hub meter export hook, BYOK docs, and 77 tests.
2026-06-24 12:50:19 +02:00

1.6 KiB

Payments and metering

Version 0.1 — SAND-WP-0006. OpenRouter-style credits for metered SaaS extensions.

Credits store

Path: ~/.local/share/sandboxer/credits.json (override via test injection).

Env Default
SANDBOXER_DEFAULT_CREDITS 10.0 USD on first use
sandboxer credits show
sandboxer credits add 25.00

Metered lifecycle

  1. createestimate_cost on metered extension; block if balance insufficient
  2. readySandboxStatus.meter.estimate_usd recorded
  3. destroymeter_actual (or prorated estimate); debit credits; State Hub note event

Self-hosted extensions (pricing_model: self-hosted) skip credits.

Extension contract

Metered extensions implement on SandboxExtension:

def estimate_cost(self, profile, inputs, *, duration_s=3600) -> MeterQuote | None
def meter_actual(self, handle, *, duration_s: float) -> float | None

Reference: ext.saas-stub (no external API).

BYOK

Provider API keys resolve at provision boundary — never stored on SandboxStatus or emitted to State Hub.

  1. Operator lookup: warden route find "<provider> API key" --json
  2. Inject env before sandboxer create (e.g. E2B_API_KEY, MODAL_TOKEN_ID)
  3. Or map secret_ref from extension config to SANDBOXER_SECRET_<REF> env

See docs/cloud-adapters.md.

Billing export

On metered destroy, optional fin-hub hook when SANDBOXER_FIN_HUB_URL is set. Posts sandbox_id, extension_id, duration_s, actual_usd to /usage/sandbox. Implementation: src/sandboxer/payments/billing_export.py.