Vertal Run documentation
Everything you need to run code safely with Vertal Run: from your first API call to running your own infrastructure.
Overview
Vertal Run is KUBO Protocol's secure code-execution platform. You send code; Vertal Run runs it in a fresh, isolated sandbox and returns the output. It was built for:
- AI agents that write and run code (data analysis, automation, tool use).
- Developer products that need to execute user code: playgrounds, courses, IDEs, notebooks.
- Platforms that want per-tenant quotas, metering and billing for code execution.
You can use it three ways: the HTTP API, the Python SDK, or the MCP server for AI agents. Supported languages today: Python 3.12, JavaScript (Node 22) and Bash 5.2.
Quickstart
1. Get an API key
Create a free account at vertalrun.com/entrar and generate a key in your dashboard, which also gives you ready-to-paste MCP, Claude Code, HTTP and SDK snippets. Keys look like kubo_sk_…. They are shown once and stored only as a SHA-256 hash, so keep yours in a secrets manager or an environment variable. An account can have up to 5 active keys and revoke any of them from the dashboard.
export KUBO_API_KEY="kubo_sk_..."
2. Run your first program
curl -X POST https://vertalrun.com/api/v1/executions \
-H "Authorization: Bearer $KUBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"language": "python", "code": "print(6 * 7)"}'
{
"id": "exe_9392448a9b514e3f90193963b7d948d0",
"status": "succeeded",
"stdout": "42\n",
"stderr": "",
"exit_code": 0,
"duration_ms": 265,
"truncated": false,
"usage": {"sandbox_seconds": 0.265},
"request_id": "req_be05ea1492f949f8a0617a4f3cd738cc"
}
3. Try it in the browser
Open the playground, paste your key and press Run (or Ctrl/⌘ + Enter).
Core concepts
| Concept | What it means |
|---|---|
| Execution | One program run. It has an id (exe_…), a status, output, an exit code and a duration. You can fetch it later. |
| Sandbox | A fresh, isolated environment created for each execution and destroyed afterwards. Nothing persists between executions. |
| Tenant | The account an API key belongs to. Executions, usage and quotas are scoped to the tenant; tenants never see each other's data. |
| Plan | Free, Pro or Enterprise. Sets daily quota, rate limit, maximum run time and sandbox memory. |
| Request ID | Every response carries request_id and an X-Request-Id header. Include it when you contact support. |
Execution status values:
| Status | Meaning |
|---|---|
succeeded | The program exited with code 0. |
failed | The program exited with a non-zero code. Read stderr and exit_code. |
timeout | The program ran longer than timeout_s; the sandbox was killed. exit_code is null. |
error | The sandbox could not start. Retry later; this is not caused by your code. |
Authentication
Send your key as a bearer token on every request except GET /health:
Authorization: Bearer kubo_sk_...
- Keep keys on your server. Never ship them in a mobile app, a browser bundle or a public repository.
- Use one key per environment (development, production) and per service.
- A revoked key stops working immediately and returns
401 unauthorized.
Operators create and revoke keys with the CLI. You can rotate your own key at any time with POST /v1/keys/rotate: you get a new key and the old one stops working immediately.
API reference
Base URL: https://vertalrun.com/api. Requests and responses are JSON (UTF-8).
POST/v1/executions
Runs code in a new sandbox and waits for it to finish.
| Field | Type | Required | Description |
|---|---|---|---|
language | string | yes | python, javascript or bash. |
code | string | yes | Program source, up to 128 KB. It is passed on standard input. |
timeout_s | number | no | Maximum run time in seconds. Default 10, capped by your plan. |
Response fields: id, status, stdout, stderr, exit_code, duration_ms, truncated (true if the output went over 64 KB per stream), usage.sandbox_seconds, request_id.
Safe retries. Add an Idempotency-Key header (1–255 characters: letters, digits, . _ : -). If the same key arrives again with the same body, you get the first result back with "idempotent_replay": true, and the code does not run or count against your quota again. The same key with a different body returns 409 idempotency_conflict.
curl https://vertalrun.com/api/v1/executions \
-H "Authorization: Bearer $KUBO_API_KEY" \
-H "Idempotency-Key: order-1234" \
-H "Content-Type: application/json" \
-d '{"language": "python", "code": "print(6 * 7)"}'
GET/v1/executions/{id}
Returns a stored execution, including language and created_at (Unix time). Only the tenant that created it can read it; anyone else gets 404.
GET/v1/usage
Returns today's usage (UTC) and your plan limits.
{
"tenant": "kubo-vibe",
"plan": "pro",
"today": {"executions": 3, "sandbox_seconds": 2.635},
"limits": {"executions_per_day": 10000, "requests_per_minute": 120, "max_timeout_s": 60}
}
POST/v1/keys/rotate
Issues a new key for your account (same plan) and revokes the key used for the call. The new key is shown once:
{"api_key": "kubo_sk_...", "key_id": "key_...", "revoked_key_id": "key_...", "plan": "pro"}
GET/v1/openapi.json
Public OpenAPI 3.1 description of the API. Import it into agent frameworks, API clients or code generators to get typed tools such as runCode.
GET/health
Public liveness check: {"status": "ok", "version": "0.2.0"}.
Errors
Errors use one shape, and never include stack traces or internal details:
{"error": {"code": "quota_exceeded", "message": "daily quota of 100 executions reached"}, "request_id": "req_..."}
| HTTP | Code | What to do |
|---|---|---|
| 400 | invalid_language, invalid_code, invalid_timeout, invalid_json, invalid_content_length, invalid_idempotency_key | Fix the request. |
| 401 | unauthorized | Check the key; it may be missing, wrong or revoked. |
| 403 | forbidden | The API origin was called directly. Use https://vertalrun.com/api. |
| 404 | not_found | Unknown endpoint, or an execution of another tenant. |
| 409 | idempotency_conflict | You reused an Idempotency-Key with a different body. Use a new key. |
| 413 | code_too_large, body_too_large | Keep code under 128 KB and the body under 256 KB. |
| 429 | rate_limited | Too many requests per minute. Wait for the Retry-After seconds and retry. |
| 429 | quota_exceeded | Daily quota reached. Wait for the next UTC day or upgrade. |
| 500 | internal | Retry; contact support with the request_id if it persists. |
| 503 | capacity_exhausted | All sandboxes are busy. Retry after Retry-After seconds, with the same Idempotency-Key. |
| 502 / 503 | api_unreachable, api_not_configured | The platform behind the edge is down or not connected yet. |
Plans & limits
| Plan | Executions / day | Requests / min | Max run time | Sandbox memory |
|---|---|---|---|---|
| Free | 100 | 10 | 10 s | 256 MB |
| Pro | 10,000 | 120 | 60 s | 1 GB |
| Enterprise | 1,000,000 | 1,200 | 300 s | 4 GB |
Every plan also has these limits:
- 1 CPU per sandbox and 64 processes.
- 16 MB writable
/tmpand 1 MB maximum file size. - No network access.
- 64 KB of output per stream.
Python SDK
The SDK has no dependencies (Python 3.10+). It is in the repository as vertal2kubo.client.
from vertal2kubo.client import KuboClient, KuboError
client = KuboClient("https://vertalrun.com/api", "kubo_sk_...") # or KUBO_API_URL / KUBO_API_KEY env vars
result = client.run("print(sum(range(10)))", language="python", timeout_s=10)
print(result["status"], result["stdout"]) # succeeded 45
print(client.get(result["id"])["created_at"])
print(client.usage()["today"])
client.run("print(1)", idempotency_key="job-42") # retry-safe: same key, same result
client.rotate_key() # new key; the client switches to it
try:
client.run("x", timeout_s=999)
except KuboError as e:
print(e.status, e.code, e.request_id) # 400 invalid_timeout req_...
CLI
# Operators (on the API host)
python -m vertal2kubo serve --host 0.0.0.0 --port 8080 --max-concurrent 4 --queue-timeout 30
python -m vertal2kubo serve --runtime runsc # every sandbox under gVisor
python -m vertal2kubo create-key acme --plan pro # prints kubo_sk_... once
python -m vertal2kubo revoke-key key_1a2b3c4d5e6f
python -m vertal2kubo purge --days 30 # delete stored outputs older than 30 days
# Clients
export KUBO_API_URL=https://vertalrun.com/api KUBO_API_KEY=kubo_sk_...
python -m vertal2kubo run "print('hello')"
python -m vertal2kubo run "console.log(6*7)" --language javascript --timeout 5
MCP for AI agents
Vertal Run ships its own MCP server (stdio, JSON-RPC 2.0). Any MCP client, including KUBO IA, Claude and IDE assistants, gets two tools. Both go through the API, so the same key, quota and metering apply.
| Tool | Input | Output |
|---|---|---|
run_code | code, language (default python), timeout_s | status, stdout, stderr, exit code, duration. Marked as an error when the program fails or the API refuses. |
get_usage | — | Today's executions, sandbox seconds, plan and limits. |
Client configuration (Claude Desktop, Claude Code and others):
{
"mcpServers": {
"vertal-run": {
"command": "python",
"args": ["-m", "vertal2kubo.mcp"],
"env": {"KUBO_API_URL": "https://vertalrun.com/api", "KUBO_API_KEY": "kubo_sk_..."}
}
}
}
run_code call starts from a clean sandbox. To carry data between steps, have the agent include it in the next program.Security
Every execution runs in its own container, which is removed when the execution ends. The container has:
- no network;
- a read-only root filesystem and a small
noexec/tmp; - all Linux capabilities dropped and
no-new-privileges; - an unprivileged user (uid 65534);
- memory, CPU, process and file-size limits;
- its own IPC namespace (
--ipc none); - a hard timeout that force-removes it.
Operators can add a second wall with gVisor (serve --runtime runsc): a user-space kernel that intercepts every system call, so an exploit of the Linux kernel inside the sandbox does not reach the host.
- Edge: traffic goes through Cloudflare (TLS, DDoS protection). The API origin only accepts requests relayed by the Vertal Run edge, using a shared secret.
- Keys: stored as SHA-256 hashes and never written to logs.
- Output: treat program output as untrusted input. The playground renders it as escaped text.
- Overload: when every sandbox is busy, requests get a fast
503withRetry-Afterinstead of waiting in an unbounded queue, and parallel bursts cannot exceed the daily quota. - Retention: operators delete stored outputs with
purge --days N.
--runtime runsc); the roadmap adds a microVM (Firecracker) driver with hardware isolation. Report vulnerabilities privately through GitHub Security Advisories.Self-hosting
You can run the whole platform on your own infrastructure.
- One-paste server (Hetzner): paste
deploy/hetzner/cloud-init.yamlas the server's cloud config. On first boot it installs Docker and gVisor, closes every inbound port except SSH, and starts the API and a Cloudflare Tunnel. It then pulls each new API image fromghcr.ioon its own. Operate it withvertal status,vertal key <name> proandvertal logs. - Any Linux VM with Docker:
docker compose -f deploy/compose.yaml --env-file deploy/.env up -d --build(2 vCPU / 4 GB to start). This starts the API and a Cloudflare Tunnel; no inbound ports are needed. - Edge + site: the
cloudflare/Worker deploys from GitHub Actions tovertalrun.com.
The step-by-step guide, with secrets and DNS, is in docs/DEPLOY.md.
Architecture
client / SDK / MCP agent
│ https://vertalrun.com/api
▼
Cloudflare edge Worker ── serves vertalrun.com (site + docs)
│ https://api.vertalrun.com (+ edge secret, via Cloudflare Tunnel)
▼
Vertal Run API ── auth · plans · quotas · rate limits · metering (SQLite)
│
▼
Sandbox engine ── one hardened container per execution
(pluggable driver: microVM next)
The engine's Driver interface lets a Firecracker microVM driver replace Docker without changing the API, SDK or MCP server. The full design is in ARCHITECTURE.md.
FAQ
Can my code access the internet?
No. Sandboxes have no network, by design.
Can I install packages?
Not at run time, because the filesystem is read-only and there is no network. The Python and Node standard libraries are available. Custom images with preinstalled packages are on the roadmap.
Does state persist between executions?
No. Each execution gets a clean sandbox.
How is usage counted?
Each execution counts once toward the daily quota (UTC). Sandbox time is reported as sandbox_seconds.
Is Vertal Run open source?
The Vertal Run code is MIT-licensed in kuboprotocol/Vertal2Kubo. Third-party components keep their own licenses.