API keys
This page shows you where to create an API key, how the SDKs find it, how to pass it per call, and how to rotate it. An API key authenticates every call your team makes to the Impello API. Calls to a sandbox itself carry a sandbox-scoped access token that the SDK attaches for you (see Network and Filesystem).
Where to find your key
Keys are created and read at dashboard.impello.ai/keys. That page is the only place a key is ever shown.
- A key belongs to the team, not to the person who made it. Every member of the team can see and manage the team's keys.
- A team can hold several keys. Give each one a name of up to 64 characters, and rename it later if you want.
- The full key is shown once, when it is created. Impello stores a hash of it, so a key you did not copy cannot be recovered, only replaced.
- The keys page lists every key the team created, with its name, a masked
value, when it was created, when it was last used and when it expires. The
reserved
dashboard-sessionkey that keeps your browser signed in is hidden, and cannot be renamed or deleted there. - A key can expire. When you create it, choose No expiration (the default), 7, 30 or 90 days, 1 year, or a custom date from tomorrow on. The key works through the end of that day, in your local time. The expiry cannot be changed later, and an expired key shows an Expired badge on the keys page.
Set it once
Export the key as IMPELLO_API_KEY and both SDKs pick it up. Nothing else on
this page is required.
export IMPELLO_API_KEY=imp_...
With the variable set, no call needs a key argument.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
const result = await sandbox.commands.run('echo hello')
console.log(result.stdout)
await sandbox.kill()Over HTTP the key travels in the X-API-Key header. The base URL is
https://api.sandbox.impello.ai.
Pass it per call
Every call that reaches the API also accepts the key as an option. A key passed this way wins over the environment variable. The example creates a sandbox with one key and lists sandboxes with another.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base', {
apiKey: process.env.TEAM_A_KEY,
})
const paginator = Sandbox.list({ apiKey: process.env.TEAM_B_KEY })
const sandboxes = await paginator.nextItems()
await sandbox.kill()You can also bind the key to a client once and use client.Sandbox (and
client.AsyncSandbox in Python) in place of the top-level classes. A
parameter passed to a single call beats the client, and the client beats the
environment. The TypeScript client needs @impello/sdk 0.3.2 or later.
import { Impello } from '@impello/sdk'
const client = new Impello({ apiKey: process.env.TEAM_A_KEY })
const sandbox = await client.Sandbox.create('base')
await sandbox.kill()What a key can do
A key acts for the whole team. It can create, connect to, list, pause, resume and kill the team's sandboxes, read their logs and metrics, change their network rules, and build, list and delete the team's templates. It cannot read, create, rename or delete API keys; the API refuses that route to a team key, and those operations live in the dashboard, behind your login.
Revoke and rotate
Delete a key on the keys page to revoke it. The deletion cannot be undone, and anything still using that key is refused.
To rotate a key without downtime:
- Create a new key on the keys page.
- Set
IMPELLO_API_KEYto the new value everywhere the old one is used, and redeploy. - Delete the old key. Its "last used" column tells you whether anything is still on it.
Key format
A key is imp_ followed by hexadecimal characters. Both SDKs check the shape
before sending a request, and the two checks are not the same. The Python SDK
requires imp_ plus hex and raises AuthenticationException on anything else.
The TypeScript SDK is looser: it also accepts the older prefix, and raises
AuthenticationError only when the key is not shaped like a key at all.
Neither check decides whether the key is a valid one; that is the API's answer.
A missing key raises the same error type, with a message pointing at the API
Keys tab on the dashboard. From @impello/sdk 0.3.2 the TypeScript message
names IMPELLO_API_KEY and shows an imp_ example key; earlier versions name
the older environment variable and show an old-prefix example key — set
IMPELLO_API_KEY to an imp_ key either way. A key the API rejects comes
back as HTTP 401, which the SDKs raise as AuthenticationError or
AuthenticationException with the message
Unauthorized, please check your credentials. — Python prefixes it with
401: . See Errors.
The TypeScript SDK can skip the shape check: pass validateApiKey: false or
set IMPELLO_VALIDATE_API_KEY=false. The Python SDK always checks; its
validate_api_key parameter is deprecated and has no effect.
A key minted before Impello moved to its own prefix cannot be made to work by
any client, and the two SDKs say so at different moments. Python refuses it
locally, raising AuthenticationException with a message naming the 2026-08-30
cutover. TypeScript lets it through the shape check, so the request goes out
and comes back as HTTP 401. Replace the key on the keys page; see
Migrate.
Other settings
Each setting is read from the environment under its IMPELLO_ name. The older
prefix is still read as a fallback, so an existing environment keeps working —
see Migrate.
| Variable | Default | What it does |
|---|---|---|
IMPELLO_API_KEY | none | The key. Starts with imp_ |
IMPELLO_DOMAIN | sandbox.impello.ai | The domain the API and the sandboxes sit on |
IMPELLO_API_URL | https://api. plus the domain | The API address |
IMPELLO_VALIDATE_API_KEY | true | Set to false to skip the key shape check. TypeScript only |
IMPELLO_DEBUG | false | Talk to a local API at http://localhost:3000 and reach sandboxes on localhost, for running the SDK against a local stack |
Most of these settings, and a few that have no environment variable, can be
passed on any call that reaches the API: Sandbox.create, Sandbox.connect,
Sandbox.list, Sandbox.kill and the rest. Where a TypeScript option is
narrower than that, the table says so.
| TypeScript | Python | Default | What it does |
|---|---|---|---|
apiKey | api_key | IMPELLO_API_KEY | The key |
domain | domain | IMPELLO_DOMAIN | The domain |
apiUrl | api_url | IMPELLO_API_URL | The API address |
requestTimeoutMs | request_timeout | 60000 ms / 60.0 s | How long one API request may take |
apiHeaders | api_headers | none | Extra headers sent with every API request |
proxy | proxy | none | Proxy for every request, including those to the sandbox. In TypeScript the Sandbox class accepts it on Sandbox.create and Sandbox.connect only, and it carries to the sandbox from there; every Template method accepts it too. From @impello/sdk 0.3.2 Template.build sends its file uploads through it as well; 0.3.1 and earlier upload them without it. TypeScript needs Node.js with the undici package. From @impello/sdk 0.3.2, on Bun, Deno, edge runtimes or in the browser, or when undici cannot be loaded, requests fail with InvalidArgumentError and are never sent without the proxy; 0.3.1 and earlier send them without it. Python accepts it on every call |
validateApiKey | validate_api_key | true | Set to false to skip the key shape check in TypeScript. The Python parameter is deprecated and has no effect |
signal | — | none | An AbortSignal that cancels the request. TypeScript only, and not accepted by Sandbox.list — pass it to paginator.nextItems({ signal }) instead |
requestTimeoutMs is milliseconds in TypeScript and request_timeout is
seconds in Python; 0 disables the request timeout in both. Neither bounds
the sandbox's own lifetime — that is timeoutMs or timeout on create,
covered in Timeouts.
Logging is a separate option rather than a variable. Pass logger to
Sandbox.create or Sandbox.connect, and the sandbox keeps using it for every
later request. In TypeScript it accepts anything shaped like console; in
Python it is a standard library logging.Logger. Without one, neither SDK logs
requests.
The TypeScript SDK also reads IMPELLO_ACCESS_TOKEN into a deprecated
accessToken option, and sends it as a bearer token. An API key is the only
credential you need; leave it unset. The Python SDK does not read it at all.
Next: Templates.