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

# Tutorial: your first API playground request, end to end

> A worked walkthrough of the API playground — pick Send SMS, fill the form, send it against sandbox, turn the request into a reusable script, trace it in Request Logs, and carry the same call to production.

# Tutorial: your first playground request, end to end

The [API playground guide](/guides/developer-api-playground) describes what the playground's three panes hold. This tutorial walks a concrete example through them: send one SMS in sandbox mode, turn that request into a script you can run from your terminal, verify what you sent in Request Logs, and promote the exact same call to production.

You need two things first:

* An Orbit account with the `owner`, `admin`, or `developer` role — those roles open **Developer → API playground**.
* One active API key. If you have none, create a sandbox key (`dv_test_sk_…`) under **Settings → API keys**.

## Step 1 — Send one request in the playground

1. Open **Developer → API playground**. Keep the **Sandbox/Live toggle** in the builder header on **Sandbox**.
2. In the left pane, pick *Messages → Send SMS* (`POST /messages`).
3. Fill the form:
   * `from` — one of your numbers in E.164, for example `+16572262362`.
   * `to` — a magic-number recipient, for example `+15005550002`. The trailing digit `2` makes the sandbox simulator return a **delivered** receipt (see [Sandbox magic numbers](/sandbox/magic-numbers)).
   * `body` — any text, for example `Hello from Orbit`.
4. Read the code pane (right). Switch it to the **cURL** tab — it already carries the full request against `https://api.orbit.devotel.io/api/v1/messages`, with a masked key in the `X-API-Key` header.
5. Hit **Send**.

The response panel shows a `2xx` status, the send duration, and the envelope: the message fields land under `data` (`id`, `status: test_sent`, the `from`/`to`/`body` you sent), and `meta.request_id` names this run. That `request_id` is the handle for everything after this tutorial — log it whenever you ask support to trace a call.

**The Send button is disabled?** The playground picks the first active key on your account that matches the current mode — a `dv_test_sk_…` key in sandbox, a `dv_live_sk_…` key in live. With no matching key, Send stays disabled until you create one under **Settings → API keys**. Sandbox Send stays a no-op in live mode as well.

**A `422` back?** The error names the bad field verbatim — a recipient that is not E.164, a `body` over the length limit. Fix the field named and resend.

## Step 2 — Turn the form values into a script

The playground runs one request at a time. To loop the same request — try every magic-number trailing digit, say — parameterize the values you just typed. The Node script below is the same POST the playground sent, with the form fields read from environment variables:

```js theme={null}
// first-playground-request.mjs — run with: node first-playground-request.mjs
const sandbox = process.env.ORBIT_SANDBOX !== "false"; // "false" switches to live
const key = sandbox ? process.env.ORBIT_SANDBOX_KEY : process.env.ORBIT_LIVE_KEY;
if (!key) throw new Error(`Set ORBIT_SANDBOX_KEY (or ORBIT_LIVE_KEY for a live send)`);

const res = await fetch("https://api.orbit.devotel.io/api/v1/messages", {
  method: "POST",
  headers: { "X-API-Key": key, "Content-Type": "application/json" },
  body: JSON.stringify({
    // The same three fields you filled in the builder
    from: process.env.ORBIT_FROM ?? "+16572262362",
    to: process.env.ORBIT_TO ?? "+15005550002",
    body: process.env.ORBIT_BODY ?? "Hello from Orbit",
  }),
});

const payload = await res.json();
console.log(res.status, res.headers.get("x-ratelimit-remaining"), payload);
```

Run it and compare the printed envelope to the playground's response panel — same `data` fields, same `meta.request_id`. Back in the playground, open the **cURL** tab in the code pane: the request rendered there is this same call in a single line. Copy it when you want the terminal version instead; the key appears masked in the preview, so paste your full key in before the snippet leaves the dashboard.

The script reads the key from an environment variable for the same reason the playground masks it: a copied snippet never carries a usable credential. Put the key in your shell profile or a secrets manager — never in the file you commit.

## Step 3 — Make the sandbox toggle a variable

The script's first line is the playground's **Sandbox/Live toggle** rewritten as an environment variable — the mode is data the script reads, not a code edit:

```bash theme={null}
ORBIT_SANDBOX=true  node first-playground-request.mjs   # simulated send, unbilled
ORBIT_SANDBOX=false node first-playground-request.mjs   # live send, billed
```

The mode-vs-key pairing holds here too — the server rejects a live request signed with a test key and vice versa, so `ORBIT_SANDBOX=false` with only `ORBIT_SANDBOX_KEY` set fails at the key check, not at the carrier.

## Step 4 — Look the request up in Request Logs

The playground's recent-request list in the right pane is a per-browser scratchpad — the last 50 runs, localStorage only. It is not where you look up what you sent last week.

The durable record is the **Request Logs console** at **Developer → Request logs** (`/[locale]/developer/request-logs`). Every API call — from the playground, from your script, from the SDKs — lands there workspace-wide, with the request and response payloads retained for a year. The page accepts deep links, so `/developer/request-logs?method=POST&path=/messages&status=5xx` opens already scoped to the failures. When a send behaves unexpectedly, find it there before re-sending — the recorded payload shows exactly what reached the API. See the [Request Logs console guide](/guides/api-request-logs-console) for the filters and payload views.

## Step 5 — Carry the same call into production

Sandbox and live differ in exactly one input: which key signs the request. There is no separate production base URL and no body change. The clear-to-production pattern keeps that one input split:

1. Set the live key in the environment — `export ORBIT_LIVE_KEY=dv_live_sk_…` — so the value never sits in source. The snippet you copied from the playground already reads `ORBIT_LIVE_KEY` in live mode; nothing in the request body changes.
2. Point the recipient at a real number. Magic-number recipients (`+1500555000x`) only simulate; in live mode the same `to` is dialed as a real destination.
3. Re-verify in Request Logs. Live sends appear in the same console; sandbox runs carry `test_mode` in the response `meta`, live runs do not — that flag is how you tell which mode a recorded call ran in.

Before you call the endpoint in anger, add an `Idempotency-Key` header per send so a retry never double-sends — the playground's generated snippet does not add one because a Send in a browser is a single deliberate action; a retrying worker is not. See [Idempotency and safe retries](/concepts/idempotency-and-safe-retries).

## See also

* [API playground](/guides/developer-api-playground) — the three panes, the sandbox/live toggle, the per-user history
* [Request Logs console](/guides/api-request-logs-console) — the workspace-wide request record
* [Sandbox magic numbers](/sandbox/magic-numbers) — deterministic delivery outcomes keyed by trailing digit
* [API Integration quickstart](/guides/api-integration) — the full REST map: base URLs, auth, webhooks, rate limits
* [Authentication](/authentication) — key formats, roles, and rotation
