Teams and the audit log
One Runtime account can have as many people as you need. They share its credit, sandboxes, other resources and keys. Each person has a role. Every change to members, keys, money and security settings is recorded in an audit log, with who made it, when, and from which address.
Every account starts with one person: its owner. Nothing changes until you invite someone.
Updated
On this page
Roles#
| What they can do | Owner | Admin | Developer | Billing |
|---|---|---|---|---|
| See resources, usage, balance, keys and members | yes | yes | yes | yes |
| Start, run and delete sandboxes and other resources, using credit | yes | yes | yes | — |
| Create API keys and approve CLI connections | yes | yes | yes | — |
| Revoke or limit a key somebody else made | yes | yes | — | — |
| Have a key make, list and revoke keys over the API | yes | yes | — | — |
| Make a key account-wide, or limit it to its own again | yes | yes | — | — |
| Make, fill and delete compartments | yes | yes | — | — |
| Add credit and see payments | yes | yes | — | yes |
| Invite, remove and change the role of members | yes | yes | — | — |
| Read the audit log | yes | yes | — | — |
| Make someone an owner, or change or remove an owner | yes | — | — | — |
- An account always has at least one owner. To hand over an account, make the new person an owner, then leave or change your own role.
- Anyone can leave an account, and anyone can revoke a key they made.
- A key can never do more than the person who made it. Runtime checks that person's role on every request. If you change someone from developer to billing, their keys become read-only immediately.
Invite people#
Owners and admins invite people at Members. Choose Invite, enter an email address, choose a role, and choose Send invitation. To change someone's role later, pick the new one in their row.
- The person gets an email with a link. The page also shows the link, so you can send it yourself.
- The link works once, for seven days. It works only for someone who signs in with that email address. A forwarded link does not work for anyone else.
- A new Runtime user signs up through the link and joins your account. A person with an existing account keeps it and joins your account too.
- Sending an invitation again to the same address replaces the first one. Withdraw cancels an invitation that has not been used.
- An invitation stays valid only while its sender could still send it. When the sender leaves, is removed, or loses the role that can invite, their open invitations are withdrawn.
- An account can have 50 open invitations and send 25 in any 24 hours.
Several accounts#
A person can belong to several accounts, such as their own account and their company's account.
- Website: choose the account from its name at the top of the sidebar. On a phone, the name sits at the left of the top bar. Runtime remembers the choice in this browser.
- Connecting an agent: when you approve a connection or a key request, the approval page asks which account it is for.
- CLI: every account you connect is saved on the machine.
Terminalnpx withruntime account add # connect another account; choose it in the browsernpx withruntime account # list them; * marks the one in usenpx withruntime account switch Acme # use Acme for every command after this- SDKs and the API: a key belongs to one account, so use that account's key.
GET /v1/menames the account and the role of the person who made the key.
Keys in a team#
Keys belong to the account, not to a person. Everyone who can see the account can see every key, and who made it, on the API keys page.
- Each key is its own agent, so the audit log and the bill show which key did what.
- A key sees and uses only the sandboxes and other resources its own agent made. A sandbox made with another key returns 404 to it, while a sandbox's name is still unique across the whole account.
- An owner or admin can make a key account-wide. It sees and uses every
sandbox, snapshot, image, volume, service and job in the account, whichever
key made it.
getOrCreatewith a name another key holds returns that sandbox. To make one, choose "Everything in the account" when you create the key, use Make account-wide on a key's row, or runruntime keys create --account-wide. Only an owner or admin can approve that command. This is how services that share sandboxes work, as a Blaxel workspace key does. - An account-wide key still acts as its own agent. The audit log names it. A wake, extension or restart it asks for is billed to it and counts against its own daily limit, even on a sandbox another key made. Job secrets stay with the person who made the key. The secrets that sandboxes use belong to the account, for every key.
- An account-wide key reaches the account only while the person who made it is an owner or admin. If that person changes to developer, the key sees only what it made again, from the next request. Developers and billing members cannot make or switch one. A read-only key already sees the whole account and is never account-wide.
- An owner or admin can put a key in a compartment when making it. It then sees only what its compartment's keys made. No other key reaches in, except an account-wide one (compartments).
- A full-access key of an owner or admin can make more keys over the API (run a swarm).
- The person who made a key sets or changes its daily spending limit. Owners and admins can limit or revoke any key. A key can also change the keys it made (run a swarm).
- When someone leaves or is removed, the keys they made are revoked in the same step. What they created, such as sandboxes, volumes and images, stays with the account.
Run a swarm#
One paid account has a coordinator and many workers. The coordinator holds a full-access key of an owner or admin (a wallet account's key is one). It makes one key per worker, each with its own daily cap.
Terminalruntime keys create --name worker-1 --daily-limit 5 # prints the key onceruntime keys ls # each worker, with its spendruntime keys usage <keyId> # one worker in fullruntime keys update <keyId> --daily-limit 10 # give a worker more roomruntime keys revoke <keyId> # when the worker is doneTypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime(); // RUNTIME_API_KEYconst worker = await runtime.keys.create({ name: "worker-1", dailyLimitMicros: 5_000_000 });// hand worker.key to the worker, then later:console.log(await runtime.keys.usage(worker.keyId));await runtime.keys.update(worker.keyId, { dailyLimitMicros: 10_000_000 });await runtime.keys.revoke(worker.keyId);Terminalcurl -sS https://api.withruntime.com/v1/keys -H "Authorization: Bearer ${RUNTIME_API_KEY}" \ -H "Idempotency-Key: worker-1" -H "Content-Type: application/json" \ -d '{"name":"worker-1","dailyLimitMicros":5000000}'curl -sS "https://api.withruntime.com/v1/usage?key=${KEY_ID}" -H "Authorization: Bearer ${RUNTIME_API_KEY}"curl -sS -X PATCH "https://api.withruntime.com/v1/keys/${KEY_ID}" -H "Authorization: Bearer ${RUNTIME_API_KEY}" \ -H "Content-Type: application/json" -d '{"dailyLimitMicros":10000000}'curl -sS -X DELETE "https://api.withruntime.com/v1/keys/${KEY_ID}" -H "Authorization: Bearer ${RUNTIME_API_KEY}"POST /v1/keystakesname, and optionallyaccess(fullorread),reach(agent, the default, oraccount) anddailyLimitMicros. It can also takesandboxesandactionsfor a key limited to sandboxes. It returns the new key once. A retry with the sameIdempotency-Keyreturns without the key.PATCH /v1/keys/{id}changes a key'sreach(agentoraccount) ordailyLimitMicros(nullremoves the limit), and returns the key asGET /v1/keyslists it. A key can change another key only to what it could make itself. It widens a key (account-wide, a larger limit, or no limit) only if it made that key, at any depth: account-wide only from an account-wide key, and the limits of the keys it made still add up to at most its own. Otherwise the request returns403 forbidden. It can narrow any key it sees: back to its own agent, or a smaller limit. A key never changes itself. A key limited to sandboxes keeps its reach. Each change is in the audit log.Each key is its own agent. A worker with reach
agentsees only its own sandboxes, and its spend and audit rows are its own.A key made by a key with reach
agentcan use what a sandbox needs (sandboxes, files, images, volumes, snapshots, previews and ports). It can also use the Apps and Functions its own agent made (create, list, deploy, roll back, delete), its own usage, and/v1/keys. Another worker's App returns 404, as for an id that does not exist. It can deploy an App or Function from an image only. A deploy that names abuildcomes from the account's repositories and is refused with403 forbidden, before any build is read. Deploy builds with a key made on the website. It can request at most 2minCopies, 2sparesand 20maxCopiesfor an App. To make a larger App, use a key made on the website. It may set an App'sreleaseWatchtoalertorrollback, neveroff. Turning it off would stop the owners hearing of a release that got worse, so that is refused with403 forbidden. It cannot give an App or Function a name that one of the account's own Apps holds. Creating or renaming with such a name returns409 name_taken. The account's own settings are refused with403 forbidden, whatever its person's role: closing the account, webhooks, telemetry exports, the audit log, credit and billing, secrets, scheduled jobs and their secrets, domains, networks, builds and repositories. For those, use a key made on the website, or make this key account-wide.The coordinator sees each worker's spend with
runtime keys lsorGET /v1/usage?key=<keyId>. It sees its own spend, the keys it made at any depth, and any key its reads already reach.Workers start from the coordinator's snapshots that carry the label
share: made-keys. Set the label when you take the snapshot, or later withPOST /v1/snapshots/{id}:update. Only snapshots the coordinator's key took itself count. Snapshots of other keys it can reach do not. The label is set on each snapshot itself and is never copied. A sandbox started from a shared snapshot, a fork's copies and kept snapshot, and a snapshot taken without labels of its own all leave outshare: made-keys. So a copy you change and snapshot again is not shared unless you label it. A worker key made before this feature was released (see the changelog) does not reach shared snapshots. Make it again. Every key under the coordinator, at any depth, can create a sandbox from such a snapshot, memory or disk. It can do nothing else with it: it cannot list, read, change or delete it. A snapshot without the label returns404 snapshot_not_foundto them. So does a labelled snapshot of a sandbox that named its egress secrets (secretson create). A copy would keep that list, and those secrets belong to the coordinator, not the worker. The coordinator can still start it. Sharing never crosses a compartment. Revoking the coordinator's key ends the sharing.TypeScript
const snapshot = await sandbox.snapshot({ labels: { share: "made-keys" } });// in a worker, with its own key:const copy = await new Runtime({ apiKey: worker.key }).sandboxes.create({ snapshot: snapshot.id,});Revoking stops a key within ten seconds. What its agent made keeps running until stopped.
Only a full-access key made by an owner or admin can do this. A read-only key, a selected-actions key, a developer's key or a key in a compartment cannot make, list or revoke keys.
A new key never has more than the key that made it. It can be account-wide only if the maker is account-wide. It keeps the maker's expiry and per-request cap. When the maker has a daily limit, every key it makes needs one. The daily limits of every live key under it, at any depth, add up to at most the maker's limit. A worker's own workers share its limit and never add to it. Keys can be made at most 8 deep. A read-only key cannot spend, so it takes no limit.
At most 100 live keys made this way per account, and 1,000 made in any 24 hours (
quota_exceeded). Revoke workers' keys when done.Each is in the audit log as
key.created, by the making key's agent, withmadeBynaming the key that made it.
A key limited to sandboxes
A key can be limited to a few sandboxes and to what it may do to them. Give it to something that needs one sandbox and should hold no key to the rest of the account. An example is a watcher that restarts a server when it stops responding.
Terminalruntime keys create --name watcher --sandbox <sandboxId> --actions get,create --daily-limit 2TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime(); // RUNTIME_API_KEYconst sandboxId = process.env.SANDBOX_ID!; // the sandbox to watchconst watcher = await runtime.keys.create({ name: "watcher", sandboxes: [sandboxId], actions: ["get", "create"], dailyLimitMicros: 2_000_000,});POST /v1/keystakessandboxes(1 to 20 ids) andactionsin place ofaccessandreach. The actions areget(read the sandbox and its metrics),create(start, wake and restart it; it never makes a sandbox),stop(stop and pause it),exec(commands, processes and the interpreter),read_fileandwrite_file.- It can call only those sandboxes' own routes, by id, and only for the actions
it was given. Everything else returns
403 forbidden: other sandboxes, lists, deleting, resizing, forking, networks, sessions, secrets, jobs, keys, the account's settings and MCP. - It sees its sandboxes whichever key made them. The making key can name only sandboxes it acts on itself, outside every compartment.
- Only
createspends, so only a key with it takes a daily limit. It needs one when the making key has one. runtime keys lsandGET /v1/keysshow it with reachsandboxes, itssandboxesand itsactions. It makes no keys.
Asked for in the browser
With no key on the machine, or with --browser, the same command asks an owner
or admin to approve the key in the browser. runtime keys create does this for
any key. Use it when a connector such as ChatGPT or Claude made the sandboxes
and nobody holds a key to make one with. You can also use it to give an agent
somewhere else a few sandboxes and nothing more:
Terminalruntime keys create --name helper --sandbox <id>,<id> --actions get,exec,read_file,write_file- It prints a link and a code. The approval page names each sandbox, what the key can do to it, and whether it can spend. The key goes to the terminal that asked, sealed to it, and is never shown anywhere else.
- Only an owner or admin approves it, for any sandbox in the account outside every compartment, whichever key made it.
- Without
create, the key cannot start, wake or restart its sandboxes. It takes no daily limit, and it places no hold of its own. A running sandbox it reaches is billed to its owner as usual. Commands the key runs count as activity, so they keep the sandbox from pausing when idle. To limit that, give the sandbox a time limit (timeoutSeconds) or stop it when done.
Leaving and removing#
On Members, use the link at the end of the person’s row and confirm:
- Leave takes you out of an account. The last owner cannot leave until there is another owner.
- Remove takes someone else out. Admins remove developers, billing members and other admins; only an owner removes an owner.
- Either way, the person loses access immediately, and their keys stop working. They can be invited back, with a new role if you like.
- What they made stays in the account. Their stopped and paused sandboxes' disks, snapshots, volumes and images are kept on the account's credit, as anyone's are, until someone deletes them. The same holds when your directory suspends someone.
Emails#
Each person chooses which of Runtime's optional emails they get, for each
account they are in, at Settings, Emails
(withruntime.com/account/emails).
Turning one off stops it for you only. Other owners still get theirs. The
account's notices (GET /v1/notices, Usage & billing) and webhooks still include
every one. Each of these emails also ends with a link that stops that kind
for you, after asking.
| Setting | What it is |
|---|---|
own-deletions |
A day before a sandbox is deleted at the date its own :retention chose, at most once a day |
billing |
When the account's credit runs low or runs out |
usage |
When the account has used 80% and all of the month's free usage |
tips |
A few getting-started emails in your first days |
Always sent, with no switch: sign-in links and invitations, a revoked key, replies in a support conversation, credit about to expire, service credits, and a warning before Runtime deletes something nothing pays for.
From code, a key reads and sets only its own person's emails, never anyone else's:
GET /v1/account/emails, and POST /v1/account/emails:update with
{"category": "own-deletions", "enabled": false}. In the CLI, use
runtime account emails and runtime account emails own-deletions off. In
MCP, runtime_account action emails reads them. Reading them needs a key
that reads usage. Changing them needs a key with every action. A read-only or
limited key returns 403 forbidden and changes nothing. A key with no
person (a wallet account's) has none, and returns 403 no_person.
Closing the account#
An owner closes the account for good on the
Close account page, linked at the foot of
Members. It can also be done from the terminal with withruntime 0.7.0 or later:
Terminalruntime account close --confirm "Acme Inc"Type the account's name exactly. runtime whoami shows it. The CLI and the API
(POST /v1/account:close with {"confirm": "<name>"}, or
runtime.account.close({ confirm }) in either SDK, from withruntime 0.7.0)
need a key for every product made by an owner. No MCP tool closes an account.
Closing cannot be undone. Immediately:
- every sandbox stops, and every snapshot, image, volume, volume backup, secret, egress secret and saved registry password is deleted;
- custom domains, dedicated addresses and the private network are released, and webhooks, telemetry exports and the upstream proxy removed;
- every key and CLI connection stops working, open invitations are withdrawn, and every member loses access.
Unspent credit from a purchase made in the last 15 days is refunded on request. Write to support@withruntime.com. Other credit, including granted and referral credit, is forfeited. Signing in again later starts a new, empty account.
Audit log#
Owners and admins read the audit log at Audit log. It records:
- Members: joined, added, removed, left, and role changes; invitations sent and withdrawn
- Keys: created and revoked, with the reason when Runtime revoked one; CLI connections and key requests approved or denied; spending limits set and removed
- Credit: top-ups started, credit bought, granted, earned by referral, refunded, disputed, taken back or expired
- Security settings: network rules, secrets created, updated, rotated, revealed and deleted (never the value), preview ports made public or private
- Creations: every sandbox, volume, image, snapshot, service and job, with
its name, labels and funding. Rules a sandbox is created with are part of its
creation. A later change is recorded as a network rules entry. Funding is
trialwhen the free usage pays for it. That covers a volume inside its 10 GiB, and a job on an account without credit. Such a job runs nothing until the account holds credit. - Sandboxes: every pause, wake, restart and stop, with who asked. For each one Runtime did itself, the entry says why: the sandbox sat idle, it reached its time limit, credit ran out, or a spending limit was hit.
- Deletions: volumes, images, snapshots, services and jobs
- The account: created, renamed, suspended and restored; the encryption key for its backups created, rotated (the old key made read-only) and destroyed
- Single sign-on: connections added, changed and removed, domains verified, single sign-on required or not
- Directory sync: SCIM tokens made and revoked, people your directory added, deactivated, reactivated or deleted, and the role each group gives
Each entry has the action; who did it (a person, a key, your directory, or Runtime itself, for things like a card payment); the time; the client's IP address; the request id; and whether it came through the website, the API or MCP. A call made by code inside one of your sandboxes also names that sandbox.
Entries are kept for at least 400 days. Nobody can edit an entry, and none is deleted before then. The page downloads the whole log, or one group of it, as a CSV file.
Read it from code
A key made by an owner or admin can read the log, if it has full access or is read-only. Entries are listed newest first, 50 at a time by default, up to 200.
Terminalcurl -H "Authorization: Bearer $RUNTIME_API_KEY" \ "https://api.withruntime.com/v1/audit?action=member.&limit=100"npx withruntime audit --action key.TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();const { events, next } = await runtime.audit.list({ action: "credit." });console.log(events.length, next);Pythonfrom withruntime import Runtimewith Runtime() as runtime: page = runtime.audit.list(action="credit.") print(len(page["events"]), page["next"])actionis one action, likekey.created, or a group ending in a dot:member.,invitation.,key.,connection.,limit.,credit.,network.,secret.,preview.,resource.,account.,sso.,scim..nextis the page's last entry. Pass it asbeforefor older entries.- MCP: the
runtime_audit_listtool, with the same filters. - A key made by a developer or billing member, or a key limited to selected
actions, gets
403 forbidden.
Sign-in and single sign-on#
People sign in with an email link, with Google, or with your company's identity provider. Single sign-on works over SAML or OIDC with Okta, Microsoft Entra ID, Google Workspace and any other standard provider. SCIM directory sync adds, updates and removes people for you. Both are free on every account. See single sign-on for the setup.
- An owner connects your identity provider for your email domain. The owner proves the domain with a DNS record. Only an owner can change single sign-on.
- Anyone on that domain who signs in through your provider joins your account with the role you choose. Someone you removed does not come back that way.
- Require single sign-on makes your provider the only way in for members. Owners can still use Google or an email link, so a broken provider cannot lock you out, and API keys keep working.
- With SCIM, deactivating someone in your directory removes them from the account and revokes every key they made, immediately. Groups in your directory decide roles: admin, developer or billing, never owner.
Try it on your own work. Sign up, then paste the setup prompt into your coding agent.