# Keys: metro init

> Create ~/.metro/.env, add a sandbox key first, and an optional production key.

Source: https://metrocli.com/docs/keys/ · Docs index: https://metrocli.com/llms.txt

`metro init` sets up your keys. It creates one private file, asks for a sandbox key, checks it with one read-only call, and leaves metro read-only.

Keys never pass through chat or your shell history. You paste them into a hidden prompt, or into the file in your editor.

## Where to get a key

You create Metronome API tokens in the Metronome app. Start with sandbox: it can't touch real billing.

| Tenant | Token page | Variable in `~/.metro/.env` |
|---|---|---|
| Sandbox | [app.metronome.com/sandbox/developer/api-tokens](https://app.metronome.com/sandbox/developer/api-tokens) | `METRONOME_SANDBOX_KEY` |
| Production (optional) | [app.metronome.com/developer/api-tokens](https://app.metronome.com/developer/api-tokens) | `METRONOME_PROD_KEY` |

Sandbox and production both call `https://api.metronome.com`. The key decides the tenant, so they must be separate tokens.

## Three ways to run it

**You, in a terminal**

In an interactive terminal, `metro init` walks four steps. The tenant summary on the "Connected" line shows your own counts.

```text
$ metro init

  metro · Metronome in your terminal

  Step 1 of 4  Create your key file
  ✓ Created ~/.metro/.env  (private: only your user can read it)

  Step 2 of 4  Add your sandbox key  (start here, it can't touch real billing)
    1. Open https://app.metronome.com/sandbox/developer/api-tokens
    2. Click "Create token", name it "metro", copy it.
    3. Paste it here (input is hidden), or press Enter to paste it into the file yourself:

  › 
  ✓ Sandbox key saved to ~/.metro/.env as METRONOME_SANDBOX_KEY
  … Checking it with a read-only call
  ✓ Connected to your Metronome sandbox · <n> customers · <n> rate cards

  Step 3 of 4  Production key  (optional, you can add it later)
    Only add this when you're ready for metro to read real billing.
    Writes to production still need write mode plus a typed confirmation for every change.
    Create one at https://app.metronome.com/developer/api-tokens
  Add a production key now? (y/N) › n
  · Skipped. Add it any time: metro init --prod

  Step 4 of 4  Safety mode
  ✓ metro is in read-only mode. It can look, preview and validate, but not change anything.
    When you want changes applied: metro mode write

  You're set. Try:
    metro status                        what metro can see
    metro catalog bind --sandbox        learn your products and rate cards
    metro ops who "Acme" --sandbox      find a customer

  Using an agent? Tell it: "read ~/.metro/AGENTS.md and run metro status"
```

Add `--plain` for no colour and ASCII glyphs. Add the production key later with `metro init --prod`.

**An agent: --agent**

`metro init --agent` never prompts. It also runs this way automatically when there is no TTY. It creates the file, copies the agent manual to `~/.metro/AGENTS.md`, sets read-only mode, and prints steps for the human:

```text
metro init (agent mode: no prompts)

✓ Created ~/.metro/.env (mode 600) with empty placeholders.

ASK THE HUMAN TO DO THIS (do not ask them to paste keys into chat):
  1. Open https://app.metronome.com/sandbox/developer/api-tokens and create a token.
  2. Open ~/.metro/.env in an editor and paste it after METRONOME_SANDBOX_KEY=
  3. Save the file and tell you "done".

Then run: metro init --check

metro is in read-only mode. Operating manual: ~/.metro/AGENTS.md
```

Run it again and the first line changes to `✓ ~/.metro/.env already exists (mode 600). metro kept every value in it.` With `--agent --prod`, the steps point at the production token page instead.

**Status: --check**

`metro init --check` reports each key as missing, rejected or working. It exits `1` while the sandbox key isn't working. With no keys set:

```text
metro init --check

  key file     ~/.metro/.env  (mode 600)
  x sandbox     missing
  . production  not set (optional). Add it any time: metro init --prod

  Next: Paste your sandbox key into ~/.metro/.env after METRONOME_SANDBOX_KEY=, then run: metro init --check
```

Agents use `--check --json`. Continue only when `keys.sandbox.status` is `working`; otherwise relay `next` verbatim:

```json
{
  "schemaVersion": "metro.init.check.v1",
  "ok": false,
  "envFile": { "path": "~/.metro/.env", "exists": true, "mode": "600" },
  "keys": {
    "sandbox": { "variable": "METRONOME_SANDBOX_KEY", "source": null, "status": "missing" },
    "production": { "variable": "METRONOME_PROD_KEY", "source": null, "optional": true, "status": "missing" }
  },
  "validation": {
    "method": "GET",
    "path": "/v1/customers?limit=100",
    "docs": "https://docs.metronome.com/api-reference/customers/list-customers",
    "readOnly": true
  },
  "next": "Paste your sandbox key into ~/.metro/.env after METRONOME_SANDBOX_KEY=, then run: metro init --check"
}
```

A key's `status` is one of `missing`, `working`, `rejected`, `unreachable`, `error`, or, for production, `same-as-sandbox`. `source` says where metro found it: `environment` or `~/.metro/.env`.

## The file metro writes

`~/.metro/.env` is created with mode `0600` inside `~/.metro` (mode `0700`). It lives outside every repo, so it can't be committed. metro never overwrites a value in it, and re-asserts mode 600 on every run.

```bash
# metro keys: this file is private to your user (chmod 600). Never commit or share it.
#
# 1) Sandbox key: start here, it can't affect real billing.
#    Create one: https://app.metronome.com/sandbox/developer/api-tokens
METRONOME_SANDBOX_KEY=
#
# 2) Production key: optional. metro is read-only until you run `metro mode write`,
#    and every production write still needs a typed confirmation.
#    Create one: https://app.metronome.com/developer/api-tokens
METRONOME_PROD_KEY=
```

`metro init` also writes `~/.metro/AGENTS.md` (the agent manual, replaced on every run) and `~/.metro/mode.json` (read-only, only if no mode is set yet).

> **Never paste a key into chat.** Not to an agent, not in an issue, not in a commit. If it happens, revoke the token in Metronome and create a new one. metro prints key fingerprints, never values.

## How the check works

metro makes one read-only call per key: `GET /v1/customers?limit=100`. When the key works, a second read-only call, `POST /v1/contract-pricing/rate-cards/list?limit=100`, fills in the tenant summary. The key only ever goes in the `Authorization` header and is never logged.

## Troubleshooting

These are the exact messages metro prints, and what to do.

| Message | Cause | Fix |
|---|---|---|
| `Metronome rejected the sandbox key. It may be revoked or copied with a missing character. Create a new one at <url> and replace the line in ~/.metro/.env.` | HTTP 401 or 403 | Create a new token, replace the line, run `metro init --check`. |
| `Couldn't reach api.metronome.com. Check your connection or proxy, then run metro init --check.` | No network, or a proxy blocks it | Fix the connection, then check again. |
| `Your sandbox and production keys are the same. Sandbox and production need separate tokens.` | Both lines hold one value | Create a sandbox token and put it on the `METRONOME_SANDBOX_KEY=` line. |
| `Metronome answered HTTP <status> to the sandbox key check. Try again in a minute: metro init --check` | Any other HTTP error | Wait, then check again. |
| `Could not make ~/.metro/.env private (mode is ..., expected 600). Run: chmod 600 ~/.metro/.env` | The filesystem refused chmod | Run the printed `chmod`. |
| `Not saved (already-set)` | The key line already has a value | metro never overwrites. Edit the line yourself. |

Press Ctrl+C at any prompt and metro stops with `Stopped. Nothing else changed. Run metro init again any time.`

## Next

Run your [first sandbox read](/docs/first-sandbox-read).
