Sandboxes
Isolate test data from production — every resource is partitioned by sandbox so you can develop, test, and demo without affecting real users.
Overview
Sandboxes provide isolated data environments within your app. Every resource in the platform — users, teams, threads, agents, configs, integrations, and more — is partitioned by sandbox. Requests authenticated with a sandbox key only see and create data in that sandbox, completely isolated from production and from other sandboxes.
Production is sandbox_id = null. A sandbox is sandbox_id = <id>. The platform enforces this at the query level automatically — you never need to filter by sandbox manually.
Every new app starts with a default sandbox named "Test" and an initial publishable key, ready to use immediately.
Creating sandboxes
Create additional sandboxes through the SDK, CLI, or developer portal:
const sandbox = await client.sandboxes.create(appId, {
name: "Staging",
slug: "staging",
});
console.log("Sandbox:", sandbox.id); // dsb_abc123
console.log("Slug:", sandbox.slug); // "staging"
Slugs must be lowercase alphanumeric with hyphens, 2-100 characters, and unique per app. They cannot start or end with a hyphen.
# CLI
archastro create sandbox -n "Staging" -s staging
Sandbox API keys
Each sandbox has its own API keys, separate from your production app keys. Two key types are available:
| Type | Prefix | Use case |
|---|---|---|
| Publishable | pk_dsb_... |
Client-side code, safe to expose |
| Secret | sk_dsb_... |
Server-side only, full access |
Creating keys
// Create a publishable key (retrievable anytime)
const { full_key } = await client.sandboxes.createKey(appId, sandbox.id, "publishable");
console.log(full_key); // pk_dsb_7xK9mQ2v_a8Yb3Zc5Wd2Qf9Gh
// Create a secret key (shown only once, then hashed)
const { full_key: secretKey } = await client.sandboxes.createKey(appId, sandbox.id, "secret");
console.log(secretKey); // sk_dsb_7xK9mQ2v_j4Km8Np2Rt6Vx0Yw — save this immediately
# CLI
archastro create sandboxkey --sandbox dsb_abc123 -t publishable
archastro create sandboxkey --sandbox dsb_abc123 -t secret
Secret keys are hashed with bcrypt on creation. The full key is returned exactly once — if you lose it, revoke and create a new one.
Revoking keys
await client.sandboxes.revokeKey(appId, sandbox.id, keyId);
archastro revoke sandboxkey dsk_abc123 --sandbox dsb_abc123
Key properties
| Field | Type | Description |
|---|---|---|
id |
string | Key ID (dsk_ prefix) |
type |
enum | publishable or secret |
key_value |
string | Full key (publishable only) |
key_hint |
string | Last 4 characters (always available) |
status |
enum | active or revoked |
last_used_at |
datetime | Updated on each authenticated request |
expires_at |
datetime | Optional expiry |
How sandbox scoping works
When a request arrives with a sandbox API key (or a sandbox-scoped JWT), the platform:
- Identifies the sandbox from the key prefix
- Resolves the sandbox context from that key
- Scopes read operations to that sandbox automatically
- Tags new records to the same sandbox automatically
This means your code doesn't change at all between production and sandbox — just use a different API key.
Production key (pk_dap_...) → production workspace
Sandbox key (pk_dsb_...) → selected sandbox workspace
Sandbox scoping applies across all major runtime and control-plane resources, including users, teams, threads, messages, agents, configs, integrations, automations, files, and secrets.
Sandbox emails
Emails sent within a sandbox are captured instead of delivered. This lets you test email flows (registration, notifications, magic links) without sending real emails.
Viewing captured emails
// List all captured emails
const emails = await client.sandboxEmails.list(appId, sandbox.id);
// Get a specific email
const email = await client.sandboxEmails.get(appId, sandbox.id, emailId);
console.log(email.subject);
console.log(email.html_body);
# CLI
archastro list sandboxmails --sandbox dsb_abc123
archastro describe sandboxmail sem_abc123 --sandbox dsb_abc123
Email properties
| Field | Type | Description |
|---|---|---|
id |
string | Email ID (sem_ prefix) |
from_name |
string | Sender name |
from_address |
string | Sender email address |
to |
array | Recipients [{name, address}] |
cc, bcc |
array | CC/BCC recipients |
subject |
string | Email subject line |
text_body |
string | Plain text content |
html_body |
string | HTML content |
headers |
object | Email headers |
Cleaning up
// Delete one email
await client.sandboxEmails.delete(appId, sandbox.id, emailId);
// Delete all emails in a sandbox
const { deleted_count } = await client.sandboxEmails.deleteAll(appId, sandbox.id);
archastro delete sandboxmail sem_abc123 --sandbox dsb_abc123
archastro delete sandboxmails --sandbox dsb_abc123 --all
Using sandboxes with the CLI
The CLI can be scoped to a sandbox so all commands operate on sandbox data:
# Activate a sandbox (opens browser to re-authenticate with sandbox scope)
archastro activate sandbox
# List sandboxes — active sandbox is marked with *
archastro list sandboxes
When a sandbox is active, the CLI token includes the sandbox_id claim. All subsequent commands (creating users, agents, threads, etc.) will operate within that sandbox.
Developer portal
The portal at developers.archastro.ai provides a visual interface for sandbox management under App → Sandboxes:
- Create and manage sandboxes
- Generate publishable and secret keys (secret keys shown once in a dismissable banner)
- View key status, hints, and last-used timestamps
- Revoke keys with confirmation
API reference
Sandbox management
| Operation | Endpoint | Description |
|---|---|---|
| List | GET /apps/:app_id/sandboxes |
List all sandboxes with keys |
| Create | POST /apps/:app_id/sandboxes |
Create a sandbox (auto-generates publishable key) |
| Show | GET /apps/:app_id/sandboxes/:id |
Get sandbox details with keys |
| Create key | POST /apps/:app_id/sandboxes/:id/keys |
Create a publishable or secret key |
| Revoke key | POST /apps/:app_id/sandboxes/:id/keys/:key_id/revoke |
Revoke a key |
Sandbox emails
| Operation | Endpoint | Description |
|---|---|---|
| List | GET /apps/:app_id/sandboxes/:id/emails |
List captured emails (newest first) |
| Show | GET /apps/:app_id/sandboxes/:id/emails/:email_id |
Get email details |
| Delete | DELETE /apps/:app_id/sandboxes/:id/emails/:email_id |
Delete one email |
| Delete all | DELETE /apps/:app_id/sandboxes/:id/emails |
Delete all emails |
Design patterns
Integration testing
Use a sandbox to run automated tests against the full platform API without affecting production:
- Create a sandbox (or use the default "Test" sandbox)
- Use the sandbox publishable key in your test suite
- Create users, agents, and threads — all isolated to the sandbox
- Verify email flows by checking captured sandbox emails
- Clean up by deleting sandbox emails between test runs
Demo environments
Create a named sandbox (e.g., demo) with pre-seeded data for customer demos. Each demo sandbox is isolated, so you can reset it independently without touching production or other sandboxes.
Staging pipeline
Use sandboxes as lightweight staging environments:
testsandbox — automated test suitestagingsandbox — manual QA and review- Production —
nullsandbox (default app keys)
All three share the same app configuration (configs, workflows, agent definitions) but have completely separate user data, threads, and state.