> ## 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.

# Sandbox magic numbers playbook: one recipe for every simulated outcome

> The sandwich guide to Orbit's sandbox test inventory — the full magic-number table per trailing digit, WhatsApp sandbox connection without Meta signup, failure-mode rehearsal, synthetic inbound replies, and the test-key-to-live-key graduation checklist.

# Sandbox Magic Numbers Playbook

The sandbox inventory that drives simulated traffic is spread across the
[sandbox test mode](/guides/sandbox-test-mode) walkthrough, the [connect
your first channel](/guides/connect-first-channel) tutorial, the [first SMS
end-to-end](/guides/first-sms-end-to-end) recipe, and the [sandbox API
cookbook](/guides/sandbox-api-samples). This playbook sandwiches the whole
inventory into one recipe: the magic-number chart, failure-mode rehearsal,
inbound injection, and the checklist that takes you from a test key to a
live key. Run it as a single script before you go live.

## 1. The big picture — a key that simulates without callers

Orbit sandbox activates on a `dv_test_sk_` API key (or a sandbox
organization, or the `X-Test-Mode: true` dashboard header). With that
signal, every send short-circuits before a provider is resolved: no
carrier is touched, no balance moves (`cost_usd_cents: 0`), and the
recipient's trailing digit decides the simulated outcome. Nothing about
your request shape changes — you graduate by swapping the key, not the
code. The three activation signals are listed on the [sandbox
overview](/sandbox/overview).

Public-form sandbox keys (`dv_test_pk_`) reach sandbox endpoints only and
can be embedded in client-side test apps; rotation preserves the form, so a
public key never flips into a secret one.

## 2. The magic test numbers chart

Send to any E.164 recipient and the **trailing digit** selects the
delivery scenario. Each scenario replays the same intermediate → terminal
sequence a real carrier produces, delivered as `message.status` webhooks
to your sandbox webhook URL:

| Trailing digit | Terminal status               | What it exercises                                    | Webhook sequence                                            |
| -------------- | ----------------------------- | ---------------------------------------------------- | ----------------------------------------------------------- |
| `1`            | never (ACK only)              | DLR-timeout / dead-letter handling                   | `sent` only, `fires_dlr: false`                             |
| `2`            | `delivered`                   | Happy path (\~50 ms terminal)                        | `sent` → `delivered`                                        |
| `3`            | `undelivered`                 | Handset reject (\~1 s)                               | `sent` → `undelivered`                                      |
| `4`            | `failed`                      | Pre-submit network failure (\~100 ms, no `sent` ACK) | `failed`                                                    |
| `5`            | `expired`                     | TTL exceeded (3 s)                                   | `sent` → `expired`                                          |
| `6`            | `unknown`                     | Carrier never reports (5 s)                          | `sent` → `unknown`                                          |
| `7`            | `rejected`                    | Carrier spam filter (\~150 ms)                       | `rejected`                                                  |
| `8`            | `blocked`                     | Suppression / opt-out (\~50 ms)                      | `blocked`                                                   |
| `9`            | `delayed` → `delivered`       | 60 s lag, eventually delivered                       | `sent` → `delivered`                                        |
| `0`            | `delivered` (carrier rewrite) | Regulatory footer appended                           | `sent` → `delivered` with `body_rewritten_by_carrier: true` |

Every webhook carries `state_class` (`intermediate` / `terminal`) and
`is_terminal`, matching the tags production stamps. The same catalog is
machine-readable from `GET /api/v1/sandbox/numbers`; the full semantics
stay canonical at [magic numbers](/sandbox/magic-numbers).

### WhatsApp window-status injection

The same trailing-digit convention drives WhatsApp sends in the sandbox.
For the reply side, inject a synthetic inbound with `channel: "whatsapp"`
— the recipient "replies," Orbit opens the 24-hour customer-service
window, and a follow-up free-form send then goes through. Check the state
your composer checks: `GET /api/v1/messages/whatsapp/window-status`. That
pair — inbound injection to open the window, then a free-form send — is
the whole template-window rehearsal, with no Meta account involved.

## 3. Recipe: connect WhatsApp inside the sandbox without Meta signup

The sandbox gives you a full WhatsApp loop — template send, simulated
receipt, injected reply, free-form follow-up — before you run Meta's
embedded signup in production.

1. Mint a sandbox key with mode **Test** under **Settings → API Keys**
   (`dv_test_sk_`).
2. Bulk-provision a deterministic fictional number from the reserved
   `+1 555 01XX` range:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/sandbox/provision-numbers \
  -H "X-API-Key: $ORBIT_SANDBOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "count": 2 }'
```

3. Send a WhatsApp message from one provisioned number to a magic
   recipient — the trailing digit picks the receipt:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/whatsapp \
  -H "X-API-Key: $ORBIT_SANDBOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+15005550002",
    "from": "+15550100",
    "type": "template",
    "template": {
      "name": "sandbox_check",
      "language": { "code": "en" },
      "components": []
    }
  }'
```

4. Inject the synthetic reply (below), then send a free-form
   `type: "text"` follow-up inside the window the injection opened.

When the same code goes to production, the connect-your-first-channel
[Recipe B](/guides/connect-first-channel) walkthrough covers the real
Meta signup, template approval, and the live `window-status` probe.

## 4. Perfecting the failure modes in the simulator

Rehearse the states your production handlers must survive. Aim each one
at the magic number whose trailing digit emits exactly that state:

| Terminal status | Trigger recipient          | Handler branch to verify                                                                                                       |
| --------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `failed`        | `+15005550004` (digit `4`) | Pre-submit retry — arrives with no `sent` ACK, so the branch must not assume an intermediate update fired                      |
| `undelivered`   | `+15005550003` (digit `3`) | Handset reject arrives \~1 s after `sent` — test the code that distinguishes "accepted, then failed" from a pre-submit failure |
| `rejected`      | `+15005550007` (digit `7`) | Policy/spam reject — verify your retry logic backs off on policy errors instead of retrying immediately                        |
| `expired`       | `+15005550005` (digit `5`) | TTL expiry — confirm your DAG accepts `expired` after `sent` and your alerting does not page on the 3 s delay                  |

Sandbox receipts never mutate stored message state — the stored message
keeps its `test_sent` status, and the receipts exist only on the webhook
stream. Your failure branch reads the same payload shape it would in
production.

## 5. Pre-conditioning inbound replies

Drive the receive side by pushing synthetic replies into your agent queue
and inbox — no forged provider webhook, no handset:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/sandbox/inbound \
  -H "X-API-Key: $ORBIT_SANDBOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+15005550002",
    "channel": "sms",
    "body": "STOP",
    "contact_name": "QA Handset"
  }'
```

The injection lands exactly like a real inbound webhook: contact,
conversation, and message rows are created, the unassigned-conversation
notification fires, and your agent's queue view refreshes.
`channel` accepts `sms`, `mms`, or `whatsapp`; a repeated sender threads
into the open conversation (`created_conversation: false`). Use it to
rehearse auto-responders, STOP-keyword handling, inbox routing, and the
24-hour WhatsApp window from section 2. Endpoint bounds and error shapes
are in the [cookbook](/guides/sandbox-api-samples).

## 6. Graduating production — test key to live key

The go-live checklist handles the cut; this is what remains intact and
what changes:

1. Run the shared five-step gate — `GET
   /api/v1/sandbox/pre-launch-checklist` — until `readyForLaunch: true`.
   It is callably with either key and always evaluates your live
   workspace, so CI and the dashboard agree. Each item is covered on the
   [pre-launch checklist](/sandbox/pre-launch-checklist) page.
2. Complete KYC and fund the balance — together they switch on live sending.
3. Mint a live key (`dv_live_sk_`) under **Settings → API Keys** and swap
   it in. The request bodies stay identical; the sandbox signal rides on
   the key, not the code.
4. Walk the human sign-off on the [go-live
   checklist](/guides/go-live-checklist) for numbers, webhooks, guardrails,
   and compliance.

Two pitfalls stay intact by design: magic recipients in live mode hit the
real carrier (the trailing-digit convention is sandbox-only), and
provisioned `provider: "sandbox"` numbers belong to the sandbox workspace
only — re-register live numbers before cutting traffic. Both the sandbox
test-mode guide and the cookbook repeat these rules; this playbook keeps
them with the inventory they affect.

## Related pages

* [Sandbox and test mode](/guides/sandbox-test-mode) — the end-to-end
  walkthrough this playbook sandwiches
* [Sandbox API cookbook](/guides/sandbox-api-samples) — request/response
  pairs for every route exercised here
* [Sandbox dashboard walkthrough](/guides/sandbox-dashboard-walkthrough) —
  the console equivalent
* [Magic numbers reference](/sandbox/magic-numbers) — canonical
  digit-to-scenario semantics
* [Pre-launch checklist](/sandbox/pre-launch-checklist) — the five-step
  gate, item by item
* [Connect your first channel](/guides/connect-first-channel) — production
  WhatsApp signup (Recipe B) after the sandbox rehearsal
