> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Operate the Developer → Sandbox dashboard

> Run the sandbox workspace from the console — toggle test mode, provision fixture numbers and contacts, drive the Virtual Phone, read the pre-launch checklist, and reset state without touching an API client.

# Operating the Developer → Sandbox dashboard

The [sandbox overview](/sandbox/overview) explains what sandbox mode is and
which API routes back it. This guide is the operator-side walkthrough: the
**Developer → Sandbox** page in the console drives those same endpoints with
a click, so you can provision test numbers, seed fixture contacts, simulate
inbound replies, and reset the workspace without writing a script.

Open it under **Developer → Sandbox**. Access is restricted to the owner,
admin, and developer roles — viewer roles don't see the page.

## What the page wraps

Every card on the page maps to one of the sandbox API routes:

| Console card           | Underlying API call                                                                           | What it does                                                             |
| ---------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Test mode              | Dashboard session flag — every request the console sends carries `X-Test-Mode: true` while on | The third activation signal from the overview; turns the whole page live |
| Pre-launch checklist   | `GET /api/v1/sandbox/pre-launch-checklist`                                                    | Reads the shared five-step go-live gate                                  |
| Virtual phone          | `POST /api/v1/sandbox/inbound`                                                                | Injects a simulated inbound SMS / MMS / WhatsApp message into your inbox |
| Provision test numbers | `POST /api/v1/sandbox/provision-numbers`                                                      | Adds deterministic fictional `+1 (555) 01XX` numbers                     |
| Spawn fixture contacts | `POST /api/v1/sandbox/spawn-fixture-contacts`                                                 | Seeds fixture contacts, optionally with open conversations               |
| Reset sandbox          | `POST /api/v1/sandbox/reset`                                                                  | Wipes contacts, conversations, and messages; releases sandbox numbers    |
| Magic numbers table    | `GET /api/v1/sandbox/numbers`                                                                 | Renders the 10-state delivery-scenario catalog                           |

Two cards are console conveniences rather than sandbox endpoints: **Default
test recipient** saves a per-user phone and email that send dialogs
pre-fill while test mode is on, and **Sandbox webhook URL** is an
org-scoped destination where sandbox event callbacks (message receipts)
are delivered — set an `https://` URL to receive the same webhook shape
production delivers, or leave it blank to disable simulated callbacks.
**Test-mode API keys** lists your `dv_test_sk_*` / `dv_test_pk_*` tokens.
The **Provider stub-status** table shows which channels actually short-
circuit in test mode (SMS, MMS, WhatsApp, Email) and which still hit the
live stack (voice, RCS, push, fax — those bill and reach real upstreams
even in test mode).

## Turn on test mode first

The top **Test mode** card mirrors the Test/Live toggle in the topbar.
Switch it on before touching anything else: while test mode is off, the
Virtual Phone and the sandbox controls cards show a warning banner, and
every mutation they drive is rejected by the backend. The toggle only
affects your browser session — it puts `X-Test-Mode: true` on the
console's requests, it does not flip the organization or anyone else's
session.

To confirm you're in sandbox context, look for the **Test mode ON**
badge on the card.

## Per-action walkthrough

### Provision test numbers

**UI path:** Sandbox controls → **Provision test numbers** — enter a
count and click **Provision numbers**.

**API call:** `POST /api/v1/sandbox/provision-numbers` with
`{ "count": <n> }`.

**Behavior and bounds:** up to **25 numbers per call**
(`MAX_PROVISION_NUMBERS` — the console input caps at the same value). The
numbers are deterministic: the same workspace always gets the same
`+1 (555) 01XX` fictional numbers for the same count, so a
reset-then-provision run sees an identical inventory. Re-provisioning the
same count is idempotent — existing rows update in place rather than
duplicate.

**Verify:** the response counts the provisioned rows, and the numbers
appear in your sandbox inventory under **Numbers**. Each carries
`provider: "sandbox"` and `monthly_cost: "0.0000"` — no carrier was
touched and nothing bills.

### Spawn fixture contacts

**UI path:** Sandbox controls → **Spawn fixture contacts** — enter a
count, choose whether to include seeded conversations (on by default),
and click **Spawn contacts**.

**API call:** `POST /api/v1/sandbox/spawn-fixture-contacts` with
`{ "count": <n>, "with_conversations": true|false }`.

**Behavior and bounds:** up to **50 contacts per call**
(`MAX_FIXTURE_CONTACTS`). Each fixture is a deterministic persona
determined by index (Ada Lovelace, Grace Hopper, …) whose phone number
ends in the trailing digit of one of the 10 magic numbers — so every
delivery scenario has a ready-made recipient. With conversations enabled,
each contact gets one open inbound SMS conversation carrying a greeting
message, which gives your inbox and auto-responder flows something to
work against immediately.

**Verify:** fixture contacts appear under **Contacts** tagged
`sandbox-fixture`; when conversations were seeded, **Inbox** shows one
open thread per contact.

### Virtual phone (Inbound)

**UI path:** **Virtual phone** card — pick a channel (SMS, MMS, or
WhatsApp), set the sender `from` in E.164 format, type a body and/or an
MMS media URL, optionally set a contact display name, and click send.

**API call:** `POST /api/v1/sandbox/inbound` with
`{ "from", "channel", "body" | "media_url", "contact_name" }`.

**Behavior and bounds:** `channel` accepts only the three
`SANDBOX_INBOUND_CHANNELS` — `sms`, `mms`, `whatsapp`. The body caps at
1600 characters, and the call is rejected unless it carries a non-empty
body or a media URL. The sender picker suggests numbers from the magic-
number table so the "handset" matches a known scenario. The injection is
a pure inbox write: it never reaches a carrier, and because it is
inbound it never touches any outbound send path.

**Verify:** open **Inbox** — the message arrives like a real reply. The
contact resolves (or is created), the conversation opens or threads, the
unread counter bumps, the inbox list live-refreshes, and a new
conversation raises the new-conversation notification — exactly the
shape a real inbound webhook produces.

### Check the pre-launch gate

**UI path:** the **Pre-launch checklist** card, near the top of the page.

**API call:** `GET /api/v1/sandbox/pre-launch-checklist`.

**Behavior:** the card renders the shared five-step gate — sandbox
workspace ready, live workspace ready, test API key minted, integration
exercises the sandbox, IP allowlist configured — each as complete or
pending, with a **Ready for launch** badge when all five complete. The
evaluator always reports against your live organization, so the result
is identical whether you read it from the sandbox or the live context,
and the [pre-launch checklist reference](/sandbox/pre-launch-checklist)
agrees with it item for item.

**Verify:** reload the card after finishing a step; a pending item flips
to complete without a page refresh.

### Reset the sandbox

**UI path:** Sandbox controls → **Reset sandbox** — confirm the dialog
that opens before the wipe runs.

**API call:** `POST /api/v1/sandbox/reset`.

**What it wipes:** every contact, conversation, and message in the
sandbox workspace, in one transaction — plus it releases every sandbox-
provisioned number (`provider: "sandbox"`). Your saved default test
recipient, the sandbox webhook URL, and your API keys are console/
org settings and survive the reset. Numbers from a real provider (a
sandbox workspace should never hold any) are untouched.

**Verify:** the response reports per-class counts
(`contacts_deleted`, `conversations_deleted`, `messages_deleted`,
`numbers_released`) so you can confirm the slate is clean, and the
sandbox inventory under **Numbers** lists only what you re-provision
afterward.

## One shared rate budget

Every sandbox mutation — reset, provision, spawn, and Virtual Phone
injection — sits under the authenticated-write rate limit: **60 requests
per minute per organization**. Console clicks, your dashboard scripts,
and direct API calls all draw from that same budget. Bulk test harnesses
that provision and reset in a loop should stay well under it; if you hit
`429`, back off and retry once the minute window clears.

## Organization switching and billing

Every account ships with a paired sandbox organization. Use the
organization switcher in the topbar to flip between your live and
sandbox workspaces — the pairing lets the pre-launch checklist evaluate
both sides from either context. The Test/Live toggle on the sandbox page
is a faster session-local way to get the same sandbox signal without
leaving your current organization.

Nothing on this page bills. Magic-number sends report
`cost_usd_cents: 0`, provisioning returns `monthly_cost: "0.0000"`, and
fixture or inbound rows carry `provider: "sandbox"` — the billing system
never sees them. When you flip to a live key or live mode, the identical
request shapes bill normally; there is no sandbox-side billing state to
clean up.

## Troubleshooting

**`403 SANDBOX_ONLY` on a mutation.** The route rejected the call
because your request context isn't sandbox. You tripped the gate — which
is the point, it protects live data. To fix, activate one of the three
signals the overview lists:

1. Use a sandbox API key (prefix `dv_test_sk_*`) — the usual cause when
   a script fails.
2. Switch into the organization flagged as sandbox — the usual cause
   when the console organization switcher is on the live org.
3. Turn on the **Test mode** toggle so the console session sends
   `X-Test-Mode: true` — the usual cause when you're working from the
   dashboard.

Any one of the three is sufficient; none is tied to the others. The
warning banners inside the Virtual Phone and Sandbox controls cards
appear precisely when the third signal is missing.

**Reset returned zero counts.** The workspace was already clean — reset
only reports what it actually deleted. Re-provision or re-spawn after
the wipe instead of assuming the wipes failed.

**Virtual Phone sent nothing.** The form rejects a blank body and a
blank media URL before it ever calls the API, and it validates the
sender as E.164 — check the inline field errors on the card, not just
the network tab.

**Voice/push/RCS/fax behave "live" in test mode.** That's expected —
check the Provider stub-status table at the bottom of the page. Only
SMS, MMS, WhatsApp, and Email short-circuit; the other channels hit
their real stacks and bill accordingly even while test mode is on. Use
`+1 555` numbers for voice tests to avoid carrier fees.

## Related pages

* [Sandbox overview](/sandbox/overview) — the concepts, the three
  activation signals, and the route/constants catalog this page operates
* [Magic numbers](/sandbox/magic-numbers) — the 10 delivery scenarios
  the fixture phones and sender suggestions key off
* [Pre-launch checklist](/sandbox/pre-launch-checklist) — the five-step
  gate the page's checklist card renders
* [Sandbox and test mode](/guides/sandbox-test-mode) — the API-side
  walkthrough with copy-pasteable curl examples
