This guide takes you from nothing to a working sandbox in Python. You'll start an isolated Firecracker microVM, run code in it, install a package, move a file in and out, and run something long in the background. Each step is a few lines you can paste.
You need Python 3.8 or newer and an EQVPS account. The SDK has no dependencies.
1. Get a token
Sandboxes are paid from your account balance, so the SDK needs an account token. Connecting your account shows the three ways to get one: the dashboard, the API, or the MCP server. Then put it in the environment:
export EQVPS_API_KEY="your-token"
No balance yet? That's fine. The first time a new account creates a sandbox without enough balance, it gets $1 of sandbox credit, valid for 14 days.
2. Install the SDK
pip install eqvps
3. Start a sandbox and run code
Save this as hello.py and run it:
from eqvps import Sandbox
with Sandbox.create(tariff="small") as sb:
print(sb.id)
r = sb.run("import platform; print(platform.python_version())")
print(r.exit_code, r.stdout)
You should see the sandbox id (sb_ and 24 more characters) and then 0 3.12.x. The sandbox started in about a second, ran the code and was deleted when the with block ended.
A few things worth knowing about the result:
r.okis true when the exit code is 0 and the command didn't time out;- a non-zero exit code is not an exception, so check
r.okyourself; stdoutandstderrare capped at 1 MiB each, andr.truncatedtells you if output was cut.
4. Install a package and run shell commands
Inside the sandbox you are root on a small Linux system with Python, Node.js, git and curl. exec runs any shell command:
from eqvps import Sandbox
with Sandbox.create(tariff="small") as sb:
sb.exec("pip install --quiet requests", timeout=55)
r = sb.run("import requests; print(requests.get('https://example.com').status_code)")
print(r.stdout) # 200
The default timeout is 30 seconds and the most a synchronous call can take is 55. Big installs belong in a background task (step 6).
5. Move files in and out
from eqvps import Sandbox
with Sandbox.create() as sb:
sb.upload("/root/data.csv", "a,b\n1,2\n3,4\n")
sb.run("""
import csv
rows = list(csv.DictReader(open('/root/data.csv')))
open('/root/sum.txt', 'w').write(str(sum(int(r['b']) for r in rows)))
""")
print(sb.download_text("/root/sum.txt")) # 6
Paths must be absolute. One transfer is limited to 5 MB; download returns bytes, download_text a string.
6. Run a long job in the background
Pass background=True and you get a task instead of waiting. It has no 55-second limit:
from eqvps import Sandbox
with Sandbox.create(tariff="standard") as sb:
task = sb.exec("for i in 1 2 3 4 5; do echo step $i; sleep 20; done", background=True)
result = task.wait(on_output=lambda out, err: print(out, end=""))
print(result.state, result.exit_code) # done 0
task.wait() polls every 2 seconds and prints new output as it arrives. You can also call task.logs() yourself, or task.kill() to stop it. While a task is running, the sandbox isn't deleted for inactivity.
What this cost
Each with block above lived for a few seconds and was billed the 60-second minimum. On small that's $0.00055 per block, so all five examples together cost about a third of a cent. Prices for every tariff, the persistent mode and spending caps are in sandbox limits and billing.
When something fails
Errors from the API are exceptions you can catch:
from eqvps import Sandbox, InsufficientBalanceError, RateLimitError
try:
with Sandbox.create() as sb:
print(sb.run("print(1)").stdout)
except InsufficientBalanceError:
print("Top up the balance")
except RateLimitError as e:
print("Too many at once, retry in", e.retry_after)
The SDK already retries 429 and 503 responses up to three times when the server says how long to wait. All 11 error classes are listed in the SDK reference.
Next steps
- The same steps in JavaScript: TypeScript sandbox SDK in 5 minutes.
- Let an AI model write the code and run it here: your first agent task in a sandbox.
- Tariffs, the trial and what's inside a sandbox: the sandbox page.
Comments
No comments yet. Be the first.