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

# Pre-launch checklist: walk the five gates to go-live

> Walk the five ordered launch steps Orbit evaluates for your live workspace — the exact remedy for each, a CI gate that fails on pending, and what the checklist deliberately does not validate.

# Pre-launch Checklist

Before your sandbox becomes production traffic, Orbit evaluates a five-step
checklist against your **live** workspace. The same checklist drives the
**Developer → Sandbox** page in the dashboard and `GET
/api/v1/sandbox/pre-launch-checklist` — one contract, so your team's
dashboard, a launch script, and an AI agent session all read the same state
instead of each carrying their own version of "did we mint the test key
yet?".

This page is the operator's walkthrough for that gate set: how to read it,
what to do when a specific item is stuck at `pending`, how to wire it into
CI, and what it does — and deliberately does not — validate.

## The five gates

1. **Sandbox workspace ready** — a paired sandbox workspace exists and is
   provisioned.
2. **Live workspace ready** — your live workspace exists and is not itself a
   test workspace.
3. **Test key minted** — at least one sandbox API key (`dv_test_sk_` or
   `dv_test_pk_`) is active on your live workspace.
4. **Integration exercised** — at least one sandbox key has authenticated a
   request, so we know your integration code actually ran against the
   sandbox.
5. **IP allowlist configured** — at least one active key on your live
   workspace carries an IP allowlist, so production credentials do not ship
   wide open.

Items evaluate independently — you can advance any `pending` item in any
order and re-read the checklist as often as you like. `readyForLaunch`
flips to `true` the moment every item reads `complete`, and nothing below
blocks gate two because gate one is still open.

## Read the checklist

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/sandbox/pre-launch-checklist \
  -H "X-API-Key: $ORBIT_KEY"
```

Call it with **either** your live key (`dv_live_sk_`) or your sandbox key
(`dv_test_sk_` / `dv_test_pk_`) — the response always reports against your
live workspace, so a script pointed at the sandbox and a dashboard session
inside the live workspace agree on the same result.

```json theme={null}
{
  "data": {
    "readyForLaunch": false,
    "isSandbox": false,
    "sandboxPairId": "org_…",
    "items": [
      { "id": "sandbox_workspace_ready", "status": "complete" },
      { "id": "live_workspace_ready", "status": "complete" },
      { "id": "sandbox_token_minted", "status": "pending" },
      { "id": "integration_exercised", "status": "pending" },
      { "id": "ip_allowlist_configured", "status": "pending" }
    ]
  }
}
```

Each item reports `complete` or `pending`. `readyForLaunch` is `true` only
when every item is complete.

## Gate by gate — the exact remedy

Every remedy below works from the dashboard **or** the API. The API write
endpoints the remedies touch enforce **fresh-scoped mutations only** — they
never read untrusted headers, they re-derive scope per request, and a
`PATCH` body is either rejected up front or validated against the current
stored document before it lands. None of these routes relies on the client
to supply scope.

### 1. `sandbox_workspace_ready`

Provision a sandbox workspace from **Developer → Sandbox**. Checklist
status flips to `complete` the first time the sandbox sibling exists.

If the sibling org is somehow gone (deprovisioned), the dashboard flow
provisions a new one on demand — you do not need a second account.

### 2. `live_workspace_ready`

A healthy paid org on live reports this as `complete` — it is the idle
state, not a blocker. If it reads `pending`, your account is either
flagged as a test workspace or the live org record was deleted; neither
can be fixed from the checklist itself. Contact support to restore the
live org.

### 3. `sandbox_token_minted`

**Dashboard path:** **Settings → API Keys → Create API key**. Pick the
**Test** environment, pick **Secret** (server-side) or **Public**
(browser/mobile), and save. The plaintext key is returned once — store it.

**API path:**

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/settings/api-keys \
  -H "X-API-Key: $ORBIT_LIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "pre-launch",
    "type": "secret",
    "mode": "test"
  }'
```

Send `"type": "public"` to mint a `dv_test_pk_` key — scoping is the
prefix, so a public test key rotates into a public test key and never
flips into a secret one.

### 4. `integration_exercised`

Authenticate **any** request with a sandbox key against a sandbox
endpoint. One request is enough — the checklist reads the key's
`last_used_at` stamp, which the auth middleware records on the first
authenticated call.

The smallest worked loop:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/sms \
  -H "X-API-Key: dv_test_sk_…" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+15005550002",
    "from": "+15550100",
    "body": "pre-launch exercise"
  }'
```

Send the request from your own integration code (the exact place your
production call lives) so "integration exercised" means "our code ran."

### 5. `ip_allowlist_configured`

**Dashboard path:** **Settings → API Keys** — open the key and add an IP
allowlist of the addresses your egress may use.

**API path:**

```bash theme={null}
curl -X PATCH \
  https://api.orbit.devotel.io/api/v1/settings/api-keys/{keyId}/allowed-ips \
  -H "X-API-Key: $ORBIT_LIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"allowed_ips": ["203.0.113.10"]}'
```

<Warning>
  **Dry-write before you patch.** `PATCH` verbs that rewrite a document
  (allowed-IPs on a key, `quiet_hours` on your organization settings,
  survivorship policy on a CDP merge) are whole-document replaces. A
  `PATCH` body is validated against the stored document as-is, but if you
  omit keys they disappear — GET the current document first, fold your
  change in, then PATCH the full document back. Do this anywhere you write
  credentials-as-a-document, not just on the checklist.
</Warning>

## Public and secret sandbox tokens

Step 3 accepts both sandbox token forms.

* **Secret form** (`dv_test_sk_`) — for server-side integrations; treat it
  like a password.
* **Public form** (`dv_test_pk_`) — for client-side integrations that embed
  the key in browser or mobile code; it can only reach sandbox endpoints
  and never bills.

Rotating a sandbox token preserves its form — a public test key rotates
into a public test key, never flips into a secret one — so re-creating a
token from the dashboard or the API never changes which side of your app
can safely hold it.

## Wire the gate into CI

Fail the launch on any `pending` item. The CLI and the raw endpoint both
read the same checklist, so pick one:

```bash theme={null}
npx --yes @devotel-orbit/cli checklist pre-launch --json \
  | jq -e '.data.readyForLaunch == true' || exit 1
```

```bash theme={null}
curl -s https://api.orbit.devotel.io/api/v1/sandbox/pre-launch-checklist \
  -H "X-API-Key: $ORBIT_KEY" \
  | jq -e '.data.readyForLaunch == true' || exit 1
```

Run the checker on a schedule (or on every merge to your launch branch),
then walk the humanised sign-off in the [production go-live
checklist](/guides/go-live-checklist). The API gate covers machine-checkable
readiness; the human gate covers everything else.

## Machine-read scoring vs human judgement

Every item on this checklist is **auto-evaluated** — the checklist never
waits on a human flag. `readyForLaunch: true` is a machine-readable
assertion that five conditions exist, computed from org rows and key
aggregates, and you can fail CI on it the moment it slips.

The **humanised sign-off** is the companion checklist at
[/guides/go-live-checklist](/guides/go-live-checklist) — account owner,
engineering lead, and compliance owner each initial their own section,
because the machine gate cannot decide whether your KYC records are right
or whether the emergency-stop drill ran.

## Common pending states — worked loop

Every gate below is re-readable and re-walkable — a `pending` item never
expires on its own. Advance the gate, re-read the checklist, and the item
flips the moment the underlying record settles.

| Item | Stuck at `pending`? Do this |
| - | - |
| `sandbox_workspace_ready` | Open **Developer → Sandbox** and provision the sandbox sibling. |
| `live_workspace_ready` | Nothing to fix — support restores a deleted/flagged live org. |
| `sandbox_token_minted` | Mint a test key under **Settings → API Keys → Create API key**. |
| `integration_exercised` | Send one sandbox request with a `dv_test_*` key from your own code. |
| `ip_allowlist_configured` | Add an IP allowlist on the live key under **Settings → API Keys**. |

The API gate is the machine-checkable half; the finished loop is when the
humanised checklist at [/guides/go-live-checklist](/guides/go-live-checklist)
is initialled too.

## What the checklist does NOT validate

The five gates answer "is your integration live-reachable?" — they are
deliberately narrow. The following areas stay **out of scope**, each with
its own page:

* **Content quality and template review** — message bodies, from-address
  hygiene, opt-out wording. See the [production go-live
  checklist](/guides/go-live-checklist).
* **Compliance posture completeness** — 10DLC brand/campaign, toll-free
  verification, country-specific rules. See [compliance
  readiness](/compliance/posture-overview) and the go-live checklist
  chapters that call these out.
* **Production readiness of templates and flows** — a working sandbox
  integration proves the wire path, not that your templates are final.
  Promote them yourself after the checklist reads green.
* **KYC status and funded balance** — the two hard gates on live traffic.
  Verified by the [Quickstart](/quickstart) Step 5, not this checklist.
* **Quiet-hours and send-gate policy** — the checklist does not validate
  `quiet_hours` or compliance posture; those live on their own pages and
  are validated at send time, not here.

A `readyForLaunch: true` read is the floor, not the ceiling — treat it as
the API gate you must clear before the humanised checklist owns the rest.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.