How to create a read-only API key for monitoring and CI
Choose Read only when you create a key at withruntime.com/account/keys, or run runtime keys create --read-only.
On Runtime a read-only key sees the whole account, every product included, and cannot start, change or spend anything. It covers products added later without being reissued, and it lasts until revoked. A dashboard or a CI check that holds one cannot start a sandbox or touch the balance, even if the key leaks (checked 25 September 2026, security).
Create one
An owner, admin or developer of the account can create a key of either kind.
- In the browser: at API keys, choose Read only.
- From a terminal: the CLI asks for the key, and a person approves it in the browser after checking the code, the key's name and its access.
Terminalruntime keys create --name grafana --read-onlyruntime keys create --name pr-checks --read-only | gh secret set RUNTIME_READ_KEYThe key is printed once, alone on standard output, and Runtime keeps only a hash of it. A billing member, an agent and an existing key cannot approve a key request (keys for CI).
What it can and cannot do
| A read-only key can read | It cannot |
|---|---|
| Every sandbox, its state, spec and cost | Create, start, stop, pause or wake anything |
| Images, volumes, snapshots, previews and network rules | Run a command or write a file |
| Account notices and the balance | Change a setting or a rule |
| Its own access and limit | Spend anything |
| The audit log, when an owner or admin made the key | See inside sandboxes: files or command output |
| See job runs or secrets |
A request to change something is refused with 403 forbidden, raised as
PermissionDeniedError in both SDKs.
Use it from code
Point the client at the key with RUNTIME_API_KEY, as with any key. This
script is the kind of thing a read-only key is for: it lists what is running
and what each sandbox is set up as, and touches nothing.
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime(); // RUNTIME_API_KEY holds the read-only keyconst page = await runtime.sandboxes.list({ state: ["running"] });for await (const sbx of page) console.log(sbx.id, sbx.info.name, sbx.state);Pythonfrom withruntime import Runtimeruntime = Runtime() # RUNTIME_API_KEY holds the read-only keyfor sbx in runtime.sandboxes.list(state=["running"]): print(sbx.id, sbx.info["name"], sbx.state)A job that must be sure it holds a read-only key can check before it starts:
TypeScriptimport { PermissionDeniedError, Runtime } from "withruntime";const runtime = new Runtime();const { access } = await runtime.limits.get();if (access !== "read") throw new Error(`expected a read-only key, got ${access}`);try { await runtime.sandboxes.create();} catch (error) { if (error instanceof PermissionDeniedError) console.log("refused, as it should be"); else throw error;}Pythonfrom withruntime import PermissionDeniedError, Runtimewith Runtime() as runtime: access = runtime.limits.get()["access"] # "full", "read" or "selected" assert access == "read", access try: runtime.sandboxes.create() except PermissionDeniedError: print("refused, as it should be")runtime limits prints the same from a terminal, and an agent on MCP calls
runtime_limits_get. access is read for a read-only key, full for one
that reaches every action, and selected for a key limited to the actions it
names (API account).
Where a read-only key fits
- Dashboards and alerting: sandbox counts, states and costs, account notices such as a paused sandbox about to expire, and the balance.
- CI checks: a pull-request job that verifies an image tag exists or that no sandbox with a given label is left running.
- Cost reports:
runtime usage --jsonandGET /v1/usagegive every figure in integer microdollars. - Audits: a read-only key made by an owner or admin reads the audit log, with who did what and from where (teams).
Mistakes to avoid
- Giving the monitoring job the deploy key. A full key in a dashboard can start sandboxes and spend credit if it leaks. Give it its own read-only key.
- Expecting command output. A read-only key sees a sandbox's state and cost but not what is inside it. A check that needs a file's contents needs a full key, ideally with a daily spending limit.
- Trying to make keys with a key. No key can create, list or revoke keys; that is done by a person, in the browser.
- Putting the key in a URL or a command line. Keep it in a secret store and
pass it as
RUNTIME_API_KEY.
Revoke a key from its row at API keys. Every key made, revoked or limited is in the audit log. For keys that can spend within a bound, see cap a sandbox's cost; for keeping a provider's key out of a sandbox entirely, see turn off sandbox internet.
Facts on this page were checked on 25 September 2026.