# Quickstart

This walks you from nothing to a delivered, security-scanned first send in about a
minute, using the `rly` command-line tool. Every step below is the same one a
customer runs — the send goes to a standard success-simulator address that accepts
any message and never bounces, so you need no real recipient to prove the workflow.

You'll: install the CLI, get an API key, create a mailbox, send a message, and read
it back with its scan verdict.

## 1. Install the CLI

The CLI is published as `rly` on both npm and PyPI. Pick one:

```bash
npm install -g rly        # Node.js 22+
# or
pipx install rly          # bundled native launcher, no Node toolchain needed
```

Both installs expose the `rly` and `replylayer` commands (they are identical — the
examples here use the shorter `rly`).

> Alpine/musl base images can't run the prebuilt binary — install with
> `npm i -g rly` on host Node 22+ instead. Full install options, platform support,
> and signature verification are covered in the [CLI reference](/docs/cli).

## 2. Get an API key

Auth is a **single API key**. Where it comes from:

1. **Sign up** at [app.replylayer.ai](https://app.replylayer.ai). Signup is
   invite-gated, and a new account is **inert** until a human completes both
   signup checks — a 6-digit code emailed to you and a 6-digit code sent by SMS
   to the mobile number supplied at signup.
   This is by design (anti-abuse): agents operate with a key a human has already
   provisioned and verified.
2. **Create an API key** in the dashboard and copy it. Keys look like
   `rly_live_<public_id>.<secret>` — the secret is shown once, so store it now.

Keys can be scoped `admin` (full account) or `agent` (bound to specific mailboxes).
For your first send an admin key is simplest. See
[Authentication](/docs/authentication) for scoping and rotation.

If a later call returns `EMAIL_NOT_VERIFIED` or `PHONE_NOT_VERIFIED`, the human
bootstrap above is incomplete — finish the indicated check in the dashboard;
don't retry the protected call in a loop. The CLI equivalents are
`rly auth verify --code <email-code>` and
`rly auth verify-phone --code <sms-code>`.

## 3. Point the CLI at your key

Provide the key via the `REPLYLAYER_API_KEY` environment variable, which wins over
any stored credential:

```bash
export REPLYLAYER_API_KEY=rly_live_<public_id>.<secret>
```

Production (`https://api.replylayer.ai`) is the default endpoint — real clients set
nothing else. Confirm auth and connectivity:

```bash
rly doctor --json
# → { "ok": true, "checks": [ ... ] }
```

`ok: true` with the `auth` check reporting `ok` means your key is live.

## 4. Create a mailbox

A mailbox is your send/receive email address. Create one:

```bash
rly mailbox create support-bot --json
# → { "id": "<mailbox-id>", "name": "support-bot", "address": "support-bot@..." }
```

The returned `address` is where inbound mail (and replies) will land.

## 5. Send your first message

Send to ReplyLayer's own first-party simulator address — it accepts every message
without bouncing, so no recipient confirmation is needed even on the free Sandbox tier.
The send is accepted immediately and a genuine `message.delivered` webhook fires a few
seconds later. The [email simulator guide](/docs/guides/simulator) covers the bounce,
complaint, suppression, inbound, and webhook-test scenarios:

```bash
rly send \
  --from support-bot \
  --to delivered@simulator.replylayer.net \
  --subject "hello" \
  --body "first send" \
  --json
```

```json
{
  "status": "sent",
  "message_id": "<message-id>",
  "scan": { "verdict": "clean" }
}
```

**Branch on the JSON `status`, not on the exit code.** `status` is one of `sent`,
`quarantined`, `blocked`, or `pending_review`; a clean first send is `sent`. A send
that *produced a message* exits `0` regardless of verdict — so a scanner block is
also exit `0` with `status: "blocked"`, while a gate-reject (rate limit, blocked
recipient, and so on) exits non-zero with a stable error `code` and creates no
message. The [CLI machine interface](/agents/cli) documents the full exit-code
contract, and [Message states & scan verdicts](/agents/messages) covers what each
status means and which are releasable.

## 6. Read it back

Read the message by id to see its stored scan result:

```bash
rly inbox read <message-id> --json
# → the message, including scan.verdict and scan.findings
```

When a real correspondent replies, the reply lands in your mailbox and you read it
the same way. To block until the next inbound arrival (for an agent loop), anchor a
cursor and wait:

```bash
SINCE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
rly --json inbox wait --mailbox support-bot --since "$SINCE" --timeout 30
# exit 0 with "message": null means "polled cleanly, nothing arrived" — not an error.
```

## About the Sandbox tier

The Sandbox is a free 30-day trial that only sends to confirmed recipients (the
success simulator above is exempt), so you can prove the workflow before you pay.
The four exact first-party simulator scenarios also bypass the cold-send
recipient-domain cap, so one Sandbox account can run all four in the same 24-hour
period. They still consume daily and cumulative Sandbox allowances. Daily send caps,
tiers, and quotas are covered in the [limits reference](/docs/limits).

## Next steps

- **[Authentication](/docs/authentication)** — key format, admin vs agent scoping,
  and rotation.
- **[REST API reference](/docs/api/messages)** — the full send / reply / read
  contract.
- **[Webhooks](/docs/webhooks)** — receive delivery, bounce, and inbound-message
  events instead of polling.
- **[Email simulator](/docs/guides/simulator)** — exercise delivery, bounce,
  complaint, inbound scanning, and quarantine without a real recipient.
- **[SDKs](/docs/sdks)** and **[MCP](/docs/mcp)** — TypeScript/Python libraries and
  the Model Context Protocol server, if you'd rather not shell out to the CLI.
- **[Building for agents](/agents)** — the machine-facing contracts: scan verdicts,
  send gates, error envelopes, and the safety model.
