Authentication
Every request to the API is authenticated with an API key sent as a bearer token. Keys are created in the dashboard, shown once, and can be revoked at any time.
Creating a key
- Open Dashboard → API keys.
- Give the key a name you will recognise later (
ci,prod-worker,laptop). - Copy the value immediately. Only a hash is stored, so the key cannot be shown again.
Keys look like aas_sk_ followed by 32 random URL-safe characters. You can have up to
10 active keys per account; create more only after revoking one. Keys are account-wide — they are not
scoped to a project or to a subset of endpoints.
Using a key
Send it in the Authorization header:
curl -sS https://sandbox-as-a-service.com/v1/account \
-H "Authorization: Bearer $AAS_API_KEY"import os
import requests
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['AAS_API_KEY']}"
account = session.get("https://sandbox-as-a-service.com/v1/account", timeout=30).json()
print(account["balance_usd"], account["limits"])const headers = {
Authorization: `Bearer ${process.env.AAS_API_KEY}`,
"Content-Type": "application/json",
};
const account = await fetch("https://sandbox-as-a-service.com/v1/account", { headers }).then((r) => r.json());
console.log(account.balance_usd, account.limits);
The Bearer prefix is required and matched case-insensitively. A key sent any other way
(query parameter, custom header, request body) is ignored and the request is rejected.
401 vs 403
| Status | error.type | Meaning |
|---|---|---|
| 401 | unauthorized | No credentials at all — the Authorization header was missing or malformed. |
| 401 | invalid_api_key | A key was sent but no active key matches it. Either it was mistyped, or it belongs to a deleted account. |
| 401 | invalid_api_key | The key exists but has been revoked. The message says so explicitly: This API key has been revoked. |
| 403 | account_suspended | The key is valid, but the account it belongs to is suspended. Authentication succeeded; authorization did not. Retrying will not help — contact support. |
In short: 401 means "we do not know who you are" and is fixed by sending a correct key. 403 means "we know who you are and the answer is still no" and is not fixed by rotating keys.
Rotating a key
There is no in-place rotation, and no grace period on a revoked key: revocation takes effect on the next request. Rotate with an overlap instead:
Create the replacement
Create a second key in the dashboard while the current one still works.
Deploy it
Roll the new value out to every environment that calls the API, and confirm traffic is flowing with it.
Check the old key is idle
Every key records a last_used_at timestamp. Wait until the old key stops moving.
Revoke the old key
Revoking is immediate and permanent. Any request still using it gets a 401.
Revoking a key
Revoke from Dashboard → API keys. A revoked key can never be un-revoked; create a new one instead. Revoking a key does not destroy sandboxes that were created with it — those keep running until they expire or you delete them. If a key leaked while sandboxes were running, revoke the key and then destroy the sandboxes.
Storing keys
- Keep keys in environment variables or a secret manager. Never commit them, and never ship them in a browser bundle or a mobile app — a key is a full-privilege credential for your account and its balance.
- Call the API from your backend. There is no CORS-friendly public key and no per-request scoping, so browser-side calls would expose the key to every visitor.
- Use a separate key per environment (CI, staging, production) so you can revoke one without an outage everywhere.
- Do not pass your API key into a sandbox through
env. Code running in the sandbox could use it to create more sandboxes and spend your balance. - Rotate on any suspicion of exposure. Revoking is free and instant.
Signed-in browser sessions
The dashboard talks to the same endpoints using its session cookie, which is why you can try calls
from a logged-in browser without a key. That is a convenience for the dashboard only — programmatic
clients should always use an API key so that revocation and last_used_at tracking work.