# metro docs (full) > Every metro docs page as markdown, in nav order. Index: https://metrocli.com/llms.txt # Overview > What metro is, the safety ladder, and a 60-second read. Source: https://metrocli.com/docs/ · Docs index: https://metrocli.com/llms.txt metro is an open-source CLI and agent toolkit for Metronome billing. It works with any Metronome tenant. You, or an agent like Claude Code, Codex or Cursor, use it to read your billing setup and change it safely. metro reads first. Every change becomes a local plan file with a `sha256:` hash. You confirm that exact hash, metro applies it, then it reads the object back and prints expected vs actual. ## The 60-second read - **What it is.** A terminal CLI, `metro`, plus an operating manual for agents (`AGENTS.md`) and an index of these docs for agents (`llms.txt`). Apache-2.0, Node 18 or newer. - **What it touches.** Customers, rate cards, packages, contracts, subscriptions and seats, credits and commits, invoices. See the [architecture primer](/docs/concepts/architecture). - **Where your keys live.** In `~/.metro/.env`, mode 600, outside every repo. You paste them in your editor. They never go through chat. - **What it does by default.** Nothing that writes. After `metro init`, metro is read-only. - **How a change lands.** Preflight, dry run, apply, readback. A readback mismatch exits `3`. - **Not affiliated with Metronome, Inc.** metro is built for Metronome. Metronome's own docs at [docs.metronome.com](https://docs.metronome.com) are the source of truth for its model. ## The safety ladder Six steps sit between your agent and production. All of them are on by default, and metro enforces them in code. **Read-only.** metro starts unable to change anything. Writes are a mode you turn on: `metro mode write` (long form `metro mode set read-write`). Drop back with `metro mode set read-only`. **Sandbox first.** Every live command takes `--sandbox` or `--prod`. metro never picks production on its own. Production needs its own key and its own flag. **Preview.** A preflight reads Metronome, writes a local plan file with the exact request bodies, and prints its `payloadHash`. Nothing has been sent. **Typed confirm.** Applying needs `--confirm-hash` with the hash of the exact preview you saw. Edit one field and apply refuses (`MTR-PLAN-002`). A live write also needs a typed token for the tenant. **Apply.** `--apply` sends exactly the planned requests to the tenant you named. Writes are retried only on HTTP 429, so a timed-out create is never sent twice. **Readback.** metro reads every object back and prints expected vs actual. Any mismatch exits `3`. A green preview is not proof; the readback is. ## What one change looks like ```bash metro mode write metro ledger-adjustment preflight --amount=500 --reason="Service credit" \ --ingest-alias=acme-corp --contract-id=00000000-0000-4000-8000-000000000002 \ --sandbox --out=ledger.json metro ledger-adjustment apply --file ledger.json --sandbox --confirm-hash sha256:... # dry run metro ledger-adjustment apply --file ledger.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` The full walkthrough is in [Credits and commits](/docs/guides/credits-and-commits). ## Exit codes | Code | Meaning | What to do | |---|---|---| | `0` | Success | Report the readback. | | `1` | Validation failure, blocked plan, missing setup or API error | Fix the input, preflight again. | | `2` | Safety refusal | Stop. Read the refusal code. Don't work around it. | | `3` | Readback mismatch | The write was accepted but the object differs. Read it fresh before doing anything else. | ## Where to go next - [Install](https://metrocli.com/docs/install/): Two commands, then metro doctor. - [Keys: metro init](https://metrocli.com/docs/keys/): Create ~/.metro/.env and add a sandbox key. - [Copy-paste setup](https://metrocli.com/docs/agents/copy-paste-setup/): Hand the whole setup to your agent in one line. - [Safety contract](https://metrocli.com/docs/agents/safety-contract/): Modes, refusals, confirm tokens and readback. --- # Install > Install metro with git clone and install-global.sh, then check it with metro doctor. Source: https://metrocli.com/docs/install/ · Docs index: https://metrocli.com/llms.txt metro needs Node 18 or newer, `git` and `npm`. It runs on macOS and Linux. **git** ```bash git clone --depth 1 https://github.com/metrocli/metro.git ~/.metro/src bash ~/.metro/src/scripts/install-global.sh metro init ``` **npm** npm publishing is coming with the first release. Until then, use the git tab. Once it's out, this replaces the first two lines: ```bash npm install -g @metrocli/metro metro init ``` **Agent** Give your agent this line. It installs metro and runs `metro init --agent` for you. ```text set up metro - https://metrocli.com/llms.txt ``` See [Copy-paste setup](/docs/agents/copy-paste-setup) for what it does, step by step. ## What install-global.sh does The script keeps a persistent checkout at `~/.metro/src` and links it, so `metro` is a real file on your `PATH`. 1. Clears any broken global `@metrocli/metro` link. 2. Clones `~/.metro/src`, or pulls with `--ff-only` if it already exists. It never deletes the checkout. 3. Runs `npm install` and `npm link` inside it. 4. Proves `metro` is on `PATH`, and refuses to finish if npm linked into its temp cache. Run it again any time to update: `bash ~/.metro/src/scripts/install-global.sh`. Set `METRO_INSTALL_DIR` to use another checkout path. > **Don't use npm install -g git+https://....** On current npm that often leaves a `metro` symlink into an empty temp checkout. You see "added 1 package", then `metro: command not found`. The script exists to avoid exactly this. ## Check the install: metro doctor `metro doctor` checks the install without touching Metronome. Add `--json` for agents. The output below is illustrative of a healthy install; your paths differ. ```text metro install doctor Healthy: yes [pass] Node.js 18+: Node 24.22.2 [pass] metro on PATH: /usr/local/bin/metro [pass] Global @metrocli/metro link: ... [info] Source checkout: ~/.metro/src ``` Each failing check prints a `fix:` line with the exact command, and doctor ends with `Next:`. The checks are: | Check | What it proves | |---|---| | `INSTALL-NODE-001` | Node 18 or newer | | `INSTALL-PATH-001` | `metro` resolves on your `PATH` | | `INSTALL-NPM-002` | The global `@metrocli/metro` link exists and isn't a temp-cache link | | `INSTALL-CHECKOUT-003` | `~/.metro/src` is a real git checkout | | `INSTALL-GH-002` | A warning only: whether the GitHub CLI is signed in | ## Troubleshooting | You see | Do this | |---|---| | `metro: command not found` after install | Run `export PATH="$(npm prefix -g)/bin:$PATH"`, then `metro doctor`. | | `~/.metro/src exists but is not a git checkout` | Open a new terminal in `~`, remove that folder yourself, and run the two git commands again. | | `ENOTDIR` on a retry | You used `npm install -g git+...` earlier. Run `install-global.sh`; step 1 clears the broken link. | ## Next - [Keys: metro init](https://metrocli.com/docs/keys/): Create your key file and add a sandbox key. - [First sandbox read](https://metrocli.com/docs/first-sandbox-read/): Your first read-only call against sandbox. --- # 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 · customers · 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 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 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). --- # First sandbox read > Your first read-only calls: metro status, catalog bind, ops who and package list against sandbox. Source: https://metrocli.com/docs/first-sandbox-read/ · Docs index: https://metrocli.com/llms.txt With a working sandbox key (`metro init --check` says `working`), you can read your tenant. Nothing on this page writes. Read-only mode allows all of it. ## 1. See what metro can see ```bash metro status ``` ```text metro status - local command center dashboard. Operator mode: read-only (reads on, writes off) Workspace intents: 14; catalog: user-bound-catalog Catalog allowlist: 20 live reads; 8 sandbox writes ``` `metro status --json` returns the same as JSON, including `liveEndpointAllowlist`: the endpoints metro may read, and the ones it may write on sandbox. `metro mode` shows the current ceiling on its own. ## 2. Learn your catalog ```bash metro catalog bind --sandbox --write ``` This discovers your rate cards, usage product, credit type and billable metric, and saves their IDs to `~/.metro/profiles.json`. From then on, plans use your real IDs instead of placeholders. Run it again after you change your catalog. Then read the summary: ```bash metro tenant snapshot show --sandbox --markdown ``` The snapshot names your account pattern: `dimensional-shared-usage`, `package-template`, `commit-grant-heavy`, `package-and-credits` or `greenfield-needed`. Agents read it before proposing a pricing change. ## 3. Find one customer `metro ops who` takes a name, UUID, email, external ID or URL: ```bash metro ops who "Acme Corp" --sandbox ``` ```text Acme Corp id: 00000000-0000-4000-8000-000000000001 external_id: acme-001 ingest_aliases: ["acme-corp"] lookup: name Active contract(s): Growth 00000000-0000-4000-8000-000000000002 since 2026-12-01T00:00:00.000Z package=00000000-0000-4000-8000-000000000003 Credits (nonzero): Complimentary credits balance=500 What change do you want? Common next steps: metro contract move-plan preflight --customer-id=00000000-0000-4000-8000-000000000001 --to= --prod metro ledger-adjustment preflight --amount= --reason="..." --customer-id=00000000-0000-4000-8000-000000000001 --prod metro contract extend-trial preflight --extend-by-days= --customer-id=00000000-0000-4000-8000-000000000001 --prod ``` The data above is illustrative. The suggested next steps always print `--prod`; on sandbox, swap it for `--sandbox`. For a stable lookup, pass an ID instead of a name: ```bash metro customer resolve --ingest-alias=acme-corp --sandbox --json metro customer balances --ingest-alias=acme-corp --sandbox --only-nonzero --json ``` > **Names are not unique.** A name lookup stops at the first exact match, because Metronome has no server-side name filter. Duplicate names later in the list aren't detected. Pass `--customer-id=` when it matters. ## 4. List packages ```bash metro package list --sandbox --json metro package list --search=annual --only-active --sandbox metro package customers --alias=growth --sandbox --json ``` `package customers` lists the contracts created from a package. ## What you just proved - The key reaches your sandbox tenant. - metro can resolve customers, contracts, balances and packages. - Nothing was written. Writes still need `metro mode write`. ## Next - [Architecture primer](https://metrocli.com/docs/concepts/architecture/): How customers, contracts, packages and rate cards connect. - [Credits and commits](https://metrocli.com/docs/guides/credits-and-commits/): Your first change, through the full ladder. --- # Copy-paste setup > Give your agent one line. It installs metro, sets up your key file, and stops for you at every step that needs a human. Source: https://metrocli.com/docs/agents/copy-paste-setup/ · Docs index: https://metrocli.com/llms.txt Paste this into Claude Code, Codex, Cursor, or any agent with a terminal: ```text set up metro - https://metrocli.com/llms.txt ``` The link is a brief written for the agent: the safety contract first, then setup steps, then how to report back. A human still does one thing: create the Metronome API token and paste it into a file. The agent does the rest. ## What your agent will do **Install metro.** ```bash git clone --depth 1 https://github.com/metrocli/metro.git ~/.metro/src && bash ~/.metro/src/scripts/install-global.sh ``` Once npm publishing is live, `npm install -g @metrocli/metro` does the same. **Create your key file.** It runs `metro init --agent`, which never prompts. That creates `~/.metro/.env` (mode 600) with empty placeholders, copies the manual to `~/.metro/AGENTS.md`, and leaves metro read-only. **Ask you to paste your sandbox key into the file.** It relays the three steps `metro init --agent` printed: open [the sandbox token page](https://app.metronome.com/sandbox/developer/api-tokens), create a token, paste it into `~/.metro/.env` after `METRONOME_SANDBOX_KEY=` in your editor, and say "done". **Check the key with a read-only call.** It runs `metro init --check --json` and continues only when `keys.sandbox.status` is `working`. Otherwise it relays the `next` field to you, word for word, and waits. **Learn your catalog.** It reads `~/.metro/AGENTS.md`, then runs `metro status --json`, `metro catalog bind --sandbox --write` and `metro tenant snapshot show --sandbox --markdown`. **Report a doorway.** One line saying what you can now do, then exactly three next actions you can say yes to, based on your tenant. For example: bind the catalog, look up your largest customer, or preview one pricing change on sandbox with nothing applied. When you ask for a change, the agent previews it, shows you the plain-English change and the `payloadHash`, waits for your yes, applies, and shows the readback. See the [safety contract](/docs/agents/safety-contract). > **Never paste keys into chat.** The agent will never ask for a key in chat. If you paste one anyway, it won't repeat it, and it will ask you to revoke that token and create a new one. Keys belong in `~/.metro/.env`, which you edit yourself. ## Notes per agent **Claude Code** Paste the line into a Claude Code session in any folder. Claude Code runs the install and `metro init --agent` in its terminal, then pauses for you to edit `~/.metro/.env`. If it asks permission to run `git`, `bash` or `metro`, approve those. Opening `.env` for you is not needed; you edit it yourself. **Codex** Codex runs in a sandbox. The install needs network access to `github.com`, and the key check needs `api.metronome.com`. If either is blocked, the brief tells Codex to name the blocked host and stop rather than retry in a loop. Allow network for the session, then paste the line again. **Cursor** Use Cursor's agent mode with terminal access. The agent runs the commands in its integrated terminal. Edit `~/.metro/.env` in any editor, including Cursor, then tell the agent "done". A hosted chat assistant without a terminal can't run metro. The brief tells it to say so and point you to [Install](/docs/install). ## Do it yourself instead Prefer to set up by hand? It's two commands and `metro init`. See [Install](/docs/install) and [Keys: metro init](/docs/keys). --- # AGENTS.md > The operating manual metro ships for agents, section by section, with what each part makes your agent do. Source: https://metrocli.com/docs/agents/agents-md/ · Docs index: https://metrocli.com/llms.txt `AGENTS.md` is the operating manual for agents. It lives at the root of the [metro repo](https://github.com/metrocli/metro/blob/main/AGENTS.md), and `metro init` copies it to `~/.metro/AGENTS.md` with a header line: ``. Point any agent at it with one sentence: "read ~/.metro/AGENTS.md and run metro status". The manual tells the agent to read all of it before any command that talks to Metronome. Below is each section, what it says, and why it's there. ## 1. What metro is What it says: metro reads your billing setup, previews changes as local files, validates them against known Metronome gotchas, and applies them only through gates. It gives the package name `@metrocli/metro`, Node 18, and the exit codes. Why: the agent needs to know that `0`, `1` and `2` mean different things. Prefer `--json`; success goes to stdout, refusals and progress to stderr. > **Exit code 3.** The manual lists codes `0`, `1` and `2`. The provisioning and ops commands add `3` for a readback mismatch. Treat `3` as "the write landed, but the object differs": read it fresh, don't re-run the plan. ## 2. Metronome in two minutes What it says: a table of every object, in data-flow order: usage events, billable metrics, products and rate cards, contracts, invoices. It ends with "Source of truth: docs.metronome.com. When a doc and this table disagree, the doc wins." Why: an agent that knows a package can't be edited won't try to edit one. The same model is in [Concepts](/docs/concepts/architecture). ## 3. Set up (agent steps) What it says: install, run `metro init --agent`, ask the human to paste the sandbox key into `~/.metro/.env` in their editor, run `metro init --check --json`, and continue only when `keys.sandbox.status` is `working`. Production comes last, and only the human adds it. Why: this is the one place the agent must stop and wait for you. It's the same flow as [Copy-paste setup](/docs/agents/copy-paste-setup). ## 4. The safety contract What it says: six rules. Read-only by default. Sandbox first. Always name the tenant. Preview, confirm, apply, read back. Production needs your explicit typed yes for that specific change. Never print keys. Why: most of these are enforced in code; the rest are behavior the agent must follow. The full version, including the typed tokens, is on [Safety contract](/docs/agents/safety-contract). ## 5. Learn the tenant before you act What it says: run these before proposing anything, and reuse the bound IDs instead of guessing. ```bash metro status --json metro catalog bind --sandbox --write metro tenant snapshot show --sandbox --markdown metro ops who "Acme" --sandbox ``` Why: the snapshot's `accountPattern` decides which shape fits a pricing change. "If something is missing, say so; do not invent IDs." ## 6. Provisioning workflow What it says: a table from goal to command. Every write is a `preflight` then an `apply`: | Goal | Command | |---|---| | Create a customer with ingest aliases | `metro customer create` | | Create a rate card | `metro ratecard create` | | Create a package | `metro package create` | | Create a contract | `metro contract create` | | Add a subscription | `metro subscription add` | | Change quantity or seats | `metro subscription set-quantity`, `metro subscription seats` | | Move a customer to another package | `metro contract move-plan` | | Extend a trial, or end a contract | `metro contract extend-trial`, `metro contract expire` | | Adjust a credit or commit balance | `metro ledger-adjustment` | | Archive a contract created by mistake | `metro contract repair-accidental` | | Replace a Stripe billing-provider config | `metro billing-provider cutover` | Why: if a command reports `Unknown command`, the installed metro is older than the manual. The agent updates metro, or falls back to `metro plan` and `metro api preview`. ## 7. Which docs and skills to load What it says: load `skills/metro/SKILL.md` for any metro task, the cookbook for workflows, and the gotchas before any write. `metro docs explain --markdown` gives focused explanations, and `metro schema --json` lists every command. Why: these are the same pages as [Reference](/docs/reference/commands), in the form an agent loads best. ## 8. Report a doorway What it says: after setup, or after any task, end with three concrete next actions the human can say yes to, based on this tenant. Why: you get a choice, not an install log. ## Keep it current Re-running `metro init` (or `metro init --agent`) replaces `~/.metro/AGENTS.md` with the copy from your installed metro. It never touches `~/.metro/.env`. --- # llms.txt > What's in /llms.txt and /llms-full.txt, and how every docs page has a plain markdown twin. Source: https://metrocli.com/docs/agents/llms-txt/ · Docs index: https://metrocli.com/llms.txt These docs ship in two forms: the pages you're reading, and plain markdown for agents. Both are built from the same source on every build, so they can't drift. ## The three files | URL | What it is | |---|---| | [`/llms.txt`](/llms.txt) | The agent brief. Safety contract first, setup by situation, how to report back, the loop for every change, then an index of every docs page. | | [`/llms-full.txt`](/llms-full.txt) | Every docs page as markdown in one file, in nav order. | | `/docs/.md` | A markdown twin of each page, for example [`/docs/keys.md`](/docs/keys.md). The docs root is `/docs/index.md`. | Every page has a **Copy Markdown** button and a **View .md** link at the top. Use them to hand one page to an agent. ## What /llms.txt says, in order 1. **Who it's for.** "You are an agent. A human gave you this file to set up metro on their machine." 2. **Safety contract.** Ten rules: read-only by default, sandbox first, always name the tenant, never ask for a key in chat, preview before every write, apply only with the approved hash, production needs a typed yes for that change, report the readback, what each exit code means, and never retry a failed apply blindly. 3. **Setup, by situation.** A: a local coding agent with a terminal runs the install and `metro init --agent`. B: a hosted chat assistant without a terminal says so and stops. C: a sandboxed agent with a blocked network names the blocked host and stops. 4. **Learn the tenant.** `metro status --json`, `metro catalog bind --sandbox --write`, `metro tenant snapshot show --sandbox --markdown`, `metro ops who`. 5. **Report a doorway.** One line, then exactly three next actions. 6. **The loop for every change.** Preview, confirm, apply, readback, with a real `metro ledger-adjustment` example. 7. **Key pages.** The sandbox and production token pages. 8. **Docs index.** One line per page: `- [Title](…/docs/page.md): description`. ## How the twins are made `scripts/gen-llms.mjs` runs before every build. It walks the docs page tree in `meta.json` order and, for each page: - writes the page as markdown with a title, its description, and a source link back to the HTML page; - turns MDX components into plain markdown: callouts become quotes, tabs become labelled sections, cards become link lists, the object diagram becomes a table; - drops MDX comments, which is where these docs keep source notes. Code blocks pass through unchanged, so every command in a twin is the same command as on the page. ## For people building on it The twins are static files. Static hosting can't vary a response by `Accept` header, so link the `.md` URL directly. Fetch `/llms.txt` first; it lists every twin. --- # Safety contract > Modes, tenant rules, refusals, confirm hashes, typed tokens, production rules and readback, as metro enforces them. Source: https://metrocli.com/docs/agents/safety-contract/ · Docs index: https://metrocli.com/llms.txt metro can change invoices, credits, contracts and customer access. This page is the contract between metro, your agent and you. Most of it is enforced in code. The rest is behavior every agent must follow. ## The rules 1. **Read-only by default.** After `metro init`, metro can look, preview and validate. Writes need `metro mode write`, and only the human decides to raise it. 2. **Sandbox first.** A change is proven on sandbox before production is discussed. 3. **Always name the tenant.** Pass `--sandbox` or `--prod`. metro never picks production on its own. 4. **Preview, confirm, apply, read back.** Every write follows the same ladder. 5. **Production needs the human's explicit typed yes in chat for that specific change.** A yes for one change never covers the next. A green preview is not authorization, and neither is a key being present. 6. **Never print keys.** Don't `cat` or echo `~/.metro/.env`. metro shows fingerprints like `sha256:80f0714120b8`, never values. ## Modes The mode is a ceiling, saved in `~/.metro/mode.json`. | Mode | Live reads | Live writes | Set with | |---|---|---|---| | `local-only` | blocked | blocked | `metro mode set local-only` | | `read-only` (default) | allowed | blocked | `metro mode set read-only` or `metro mode reset` | | `read-write` | allowed | allowed, with confirmation tokens | `metro mode write` or `metro mode set read-write` | `metro mode` shows the current mode. A dry run never needs write mode. An `--apply` in read-only mode is refused with `MTR-MODE-WRITE-BLOCKED` and the next command to run. ## The ladder for every write **Preflight.** Reads only. Writes a plan file with the exact request bodies and prints a `payloadHash`: the `sha256:` of the canonical plan, which covers the tenant and the key fingerprint. ```bash metro contract expire preflight --ingest-alias=acme-corp --cutover-mode=next-hour --sandbox --out=expire.json ``` **Review.** The agent shows you the plain-English change and the hash, then waits for your yes. **Dry run.** `apply` with `--confirm-hash` and without `--apply` prints the requests and writes nothing. ```bash metro contract expire apply --file expire.json --sandbox --confirm-hash sha256:... ``` **Apply.** Add `--apply` and the typed token for the tenant. ```bash metro contract expire apply --file expire.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` **Read back.** metro reads each object back and prints expected vs actual. Any mismatch exits `3`. Every apply writes a log to `~/.metro/logs//`, or to `METRO_LOG_DIR`. ## Typed tokens | Where | Flag | |---|---| | Sandbox write | `--confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX` | | Production write | `--prod --confirm-prod-apply=I_UNDERSTAND_BILLING_SIDE_EFFECTS` | | Guarded read (`metro api read`) | `--confirm-live-read I_UNDERSTAND_THIS_WILL_READ_LIVE_METRONOME` | | Guarded sandbox write (`metro api apply`) | `--confirm-live-apply I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX`, plus an apply gate and an approval record | The guarded `metro api apply` chain is sandbox-only. Production apply through it is blocked. ## Refusals A refusal exits `2`. Stop, quote it to the human, and don't work around it. | Code | When | |---|---| | `MTR-TENANT-001` | No `--sandbox` or `--prod`. metro never infers the tenant. | | `MTR-TENANT-003` | Both flags passed, or apply's tenant differs from the plan's. A sandbox plan can never be applied to production. | | `MTR-TENANT-004` | The key fingerprint changed between preflight and apply. | | `MTR-TENANT-KEY-001` | The tenant's key isn't set. | | `MTR-TENANT-KEY-002` | `--prod`, and the production key equals the sandbox key. | | `MTR-TENANT-KEY-003` | `--sandbox`, and the sandbox key equals the production key. | | `MTR-PLAN-001` | The file isn't a plan for this command. | | `MTR-PLAN-002` | The plan was edited after preflight. | | `MTR-HASH-001`, `MTR-HASH-002` | `--confirm-hash` is missing, or doesn't match the plan. | | `MTR-MODE-WRITE-BLOCKED` | `--apply` while the mode is `read-only` or `local-only`. | | `MTR-LIVE-APPLY-001` | A sandbox apply without the sandbox token. | | `MTR-PROD-APPLY-BLOCKED` | A production apply without the production token. | Two non-refusal stops matter too. `MTR-PRECHECK` (exit `1`) means live state changed since preflight; run preflight again. `MTR-APPLY-STEP-FAILED` (exit `1`) names the step that failed and the steps that completed before it. ## Production rules Before any production write, write down: 1. The customer's identifiers: Metronome customer ID, contract ID, billing-provider customer ID, and any external ID you matched on. 2. The tenant, and which key metro will use. 3. The current state, from read-only evidence. 4. The desired state, in business terms. 5. The exact endpoints and payload shapes. 6. The expected invoices, balance changes, billing-provider behavior and access effects. 7. The dry-run result, and where its file was written. 8. A canary: one customer or one object first. 9. The readback you'll run. 10. Rollback or remediation. ## Readback The samples below are illustrative, in the exact format metro prints. Readback is the proof. A `200` from Metronome is not: some contract edits return `200` and silently don't apply. ```text Applied (sandbox). Read-back (expected vs actual): ok contract.id: expected "00000000-0000-4000-8000-000000000002" actual "00000000-0000-4000-8000-000000000002" ok contract.ending_before: expected "2026-12-01T19:00:00.000Z" actual "2026-12-01T19:00:00.000Z" Log: ~/.metro/logs/contract-expire/apply-2026-11-03T19-21-34-560Z.json ``` When it fails, metro says so and exits `3`: ```text Applied, but read-back FAILED (sandbox). Read-back (expected vs actual): FAIL quantity at 2027-02-01T00:00:00.000Z: expected 15 actual 12 ``` Don't re-run the same plan. Use the log and a fresh read, for example `metro ops who --sandbox`, to find where expected and actual diverge. Fix the cause, then preflight again. ## Retries Writes are retried only on HTTP 429. A timed-out create is never sent twice. Every write metro builds carries a `uniqueness_key` where Metronome accepts one, so a repeat returns `409` instead of a duplicate. Customer and rate-card creates have no uniqueness key, so metro uses the ingest aliases and the card name as the anchor and checks them again just before writing. --- # Provision a package > Goal, preview, confirm, apply and readback for a new package. Source: https://metrocli.com/docs/guides/provision-a-package/ · Docs index: https://metrocli.com/llms.txt ## Goal Publish a new package, `growth`, on an existing rate card, then create the customer who will use it. Next you'll [create their contract](/docs/guides/create-a-contract). A package is a contract template: rate card, billing settings, and optionally commits, credits and subscriptions. It can't be edited after create, so the preview is the moment to get it right. See [Packages](/docs/concepts/packages). > **Before you start.** Run everything on sandbox first. Writes need `metro mode write`. You need a rate card ID; [Plans and rate cards](/docs/guides/plans-and-rate-cards) creates one, and `metro catalog bind --sandbox --write` finds the ones you have. ## Preview Write the spec. It is the `POST /v1/packages/create` body, in YAML or JSON. ```yaml # package.yaml name: Acme Growth rate_card_id: 00000000-0000-4000-8000-000000000103 aliases: - name: growth billing_provider: stripe delivery_method: direct_to_billing_provider usage_statement_schedule: frequency: MONTHLY day: CONTRACT_START ``` ```bash metro package create preflight --file=package.yaml --sandbox --out=plans/package.json ``` ```text metro package create preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. package: null -> {"name":"Acme Growth",...,"uniqueness_key":"metro-package-ec3d42f870c9802d24271817"} Steps: POST /v1/packages/create Payload hash: sha256:d7d5e302bc0d944254b774d65cdc122feed8befba2092e5b48a98064f36462b6 Wrote plan: ./plans/package.json ``` What preflight checks and fixes: - **`uniqueness_key`.** If the spec has none, metro derives one, at most 128 characters, and checks it against every package, archived ones too. - **Aliases.** Refuses an alias another package already holds live. To publish a new version behind an existing alias, use [Clone a package version](/docs/guides/clone-a-package-version), or pass `--allow-alias-takeover` with a future `starting_at` on the alias. - **Offsets.** String offsets such as `"0"` become integers. - **Subscriptions.** Each needs `subscription_rate`, `collection_schedule` and `proration`. `QUANTITY_ONLY` needs `initial_quantity`; `SEAT_BASED` needs `seat_config`. Then the customer, with an ingest alias, an external ID and a Stripe customer: ```bash metro customer create preflight --name="Acme Corp" --ingest-alias=acme-corp \ --external-id=acme-001 \ --stripe-customer-id=cus_ACME123 --stripe-collection-method=charge_automatically \ --sandbox --out=plans/customer.json ``` ```text metro customer create preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. customer: null -> {"name":"Acme Corp","ingest_aliases":["acme-corp"],"custom_fields":{"external_id":"acme-001"},"customer_billing_provider_configurations":[{"billing_provider":"stripe","delivery_method":"direct_to_billing_provider","configuration":{"stripe_customer_id":"cus_ACME123","stripe_collection_method":"charge_automatically"}}]} Steps: POST /v1/customers Payload hash: sha256:4c30b21c141f845e307c9eb8c89070b92e06342406d2819a678c649621bf55f8 Wrote plan: ./plans/customer.json ``` Creating a customer takes no uniqueness key, so the ingest aliases are the anchor. Preflight refuses an alias held by any customer, active or archived, and a custom-field key the tenant doesn't have. ## Confirm Read the diff lines and the hash. An agent shows you both and waits for your yes. Then dry-run, which prints the exact requests and writes nothing: ```bash metro package create apply --file plans/package.json --sandbox \ --confirm-hash sha256:d7d5e302bc0d944254b774d65cdc122feed8befba2092e5b48a98064f36462b6 ``` If anyone edits the plan file, apply refuses with `MTR-PLAN-002`. Change the spec and preflight again; a changed field means a new hash. ## Apply ```bash metro package create apply --file plans/package.json --sandbox \ --confirm-hash sha256:d7d5e302bc0d944254b774d65cdc122feed8befba2092e5b48a98064f36462b6 \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX metro customer create apply --file plans/customer.json --sandbox \ --confirm-hash sha256:4c30b21c141f845e307c9eb8c89070b92e06342406d2819a678c649621bf55f8 \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` Customer apply checks the aliases again just before writing, so running the same plan twice fails instead of creating a second customer. On production, swap `--sandbox` and the token for `--prod --confirm-prod-apply=I_UNDERSTAND_BILLING_SIDE_EFFECTS`, after a typed yes for this change. ## Readback metro reads both objects back. Every line must say `ok`; any `FAIL` exits `3`. The package readback compares the created package with the spec field by field (`package.name`, `package.rate_card_id` and the rest) and checks `package.aliases`. The customer readback: ```text Applied (sandbox). Read-back (expected vs actual): ok customer.id: expected "present" actual "present" ok customer.name: expected "Acme Corp" actual "Acme Corp" ok customer.ingest_aliases: expected ["acme-corp"] actual ["acme-corp"] ok customer.custom_fields: expected {"external_id":"acme-001"} actual {"external_id":"acme-001"} ok billing provider stripe: expected {"stripe_customer_id":"cus_ACME123","stripe_collection_method":"charge_automatically"} actual {...same...} Log: ~/.metro/logs/customer-create/apply-2026-11-03T19-21-34-560Z.json ``` Check the package again any time with `metro package list --alias=growth --sandbox --json`. Next: [Create a contract](/docs/guides/create-a-contract). --- # Create a contract > Create a contract from a package, with preview and readback proof. Source: https://metrocli.com/docs/guides/create-a-contract/ · Docs index: https://metrocli.com/llms.txt ## Goal Put Acme Corp on the `growth` package from 1 December 2026, 00:00 UTC. The customer and the package already exist; see [Provision a package](/docs/guides/provision-a-package). ## Preview ```bash metro contract create preflight --ingest-alias=acme-corp --package-alias=growth \ --starting-at=2026-12-01T00:00:00.000Z --sandbox --out=plans/contract.json ``` ```text metro contract create preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. contract: null -> {"customer_id":"00000000-0000-4000-8000-000000000101","starting_at":"2026-12-01T00:00:00.000Z","package_id":"00000000-0000-4000-8000-000000000104","uniqueness_key":"metro-contract-33ff039a22b5b61ae9e1c3fc"} Steps: POST /v1/contracts/create WARNING [MTR-MOVE-EMPTY-PACKAGE-001]: Package 00000000-0000-4000-8000-000000000104 has no commits, credits, subscriptions or scheduled charges. Payload hash: sha256:... Wrote plan: ./plans/contract.json ``` What preflight does: - **Pins the package.** It resolves `growth` to the package live at `starting_at` and writes that `package_id` into the plan. If the alias moves before you apply, you still get the package you previewed. - **Sends only allowed fields.** A package contract takes `customer_id`, `starting_at`, `package_id`, `uniqueness_key`, `transition` and `custom_fields`. Anything else returns `400` from Metronome, so metro doesn't send it. - **Refuses overlaps.** Two concurrent contracts bill twice, so preflight refuses one that overlaps an existing contract. Pass `--allow-concurrent` only if that is what you want. To move a customer between packages, use [Move a customer](/docs/guides/move-a-customer). - **Needs an hour.** `--starting-at` must fall exactly on a UTC hour. The warning above means the package bills nothing by itself yet. That's expected for a usage-only package; read it before you confirm. ### A contract without a package Write a spec with `rate_card_id` or `rate_card_alias`, plus `subscriptions[]`, `commits`, `billing_provider_configuration` and the other create fields: ```bash metro contract create preflight --file=contract.yaml --customer-id=00000000-0000-4000-8000-000000000101 --sandbox --out=plans/contract.json ``` Every subscription in the spec is checked the same way as in a package. ## Confirm Show the human the customer, the package, the start date, any warning and the hash. Then dry-run: ```bash metro contract create apply --file plans/contract.json --sandbox --confirm-hash sha256:... ``` ## Apply ```bash metro contract create apply --file plans/contract.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` ## Readback ```text Applied (sandbox). Read-back (expected vs actual): ok contract.id: expected "present" actual "present" ok contract.customer_id: expected "00000000-0000-4000-8000-000000000101" actual "00000000-0000-4000-8000-000000000101" ok contract.starting_at: expected "2026-12-01T00:00:00.000Z" actual "2026-12-01T00:00:00.000Z" ok contract.uniqueness_key: expected "metro-contract-33ff039a22b5b61ae9e1c3fc" actual "metro-contract-33ff039a22b5b61ae9e1c3fc" ok contract.package_id: expected "00000000-0000-4000-8000-000000000104" actual "00000000-0000-4000-8000-000000000104" ``` For a direct contract with subscriptions, the readback also checks the subscription count, each product and frequency, and the initial quantity. Confirm the result from the customer's side with `metro ops who "Acme Corp" --sandbox`. --- # Plans and rate cards > Change plans and rate cards, including dimensional rate cards. Source: https://metrocli.com/docs/guides/plans-and-rate-cards/ · Docs index: https://metrocli.com/llms.txt ## Goal Create the `Acme Standard` rate card with a $49 monthly seat price and a 2-cent usage price, then add a rate to it later. Prices are in cents. See [Rate cards](/docs/concepts/rate-cards). ## Preview Every rate needs `product_id`, `starting_at`, `entitled` and `rate_type`. Each `starting_at` must fall on a UTC hour. A `SUBSCRIPTION` rate needs a `billing_frequency` that matches the subscriptions that will use it. ```yaml # ratecard.yaml name: Acme Standard aliases: - name: acme_standard rates: - product_id: 00000000-0000-4000-8000-000000000010 # SUBSCRIPTION product starting_at: 2026-12-01T00:00:00.000Z entitled: true rate_type: SUBSCRIPTION price: 4900 billing_frequency: MONTHLY - product_id: 00000000-0000-4000-8000-000000000011 # USAGE product starting_at: 2026-12-01T00:00:00.000Z entitled: true rate_type: FLAT price: 2 ``` ```bash metro ratecard create preflight --file=ratecard.yaml --sandbox --out=plans/ratecard.json ``` ```text metro ratecard create preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. rate card: null -> {"name":"Acme Standard","aliases":[{"name":"acme_standard"}],"rates":"2 rates"} Steps: POST /v1/contract-pricing/rate-cards/create ; POST /v1/contract-pricing/rate-cards/addRates Payload hash: sha256:98ebc15e78183261ab2d2405a404baeb4648ff08a9178473dfe05543f182d868 Wrote plan: ./plans/ratecard.json ``` What preflight checks: - **The name is the anchor.** Rate-card create has no uniqueness key, so metro refuses a name that already exists, at preflight and again just before writing. - **Aliases stay put.** In Metronome a new card silently takes an alias from the card that holds it. metro refuses that unless you pass `--allow-alias-move`. - **Every product.** Each must exist and not be archived. A `SUBSCRIPTION` rate must point at a `SUBSCRIPTION` product. - **`addRates` only**, at most 100 rates per call. ## Confirm Read the steps and the hash, then dry-run. The dry run shows `"rate_card_id":"$step:create.data.id"`: metro fills that in with the ID the create step returns. ```bash metro ratecard create apply --file plans/ratecard.json --sandbox \ --confirm-hash sha256:98ebc15e78183261ab2d2405a404baeb4648ff08a9178473dfe05543f182d868 ``` ## Apply ```bash metro ratecard create apply --file plans/ratecard.json --sandbox \ --confirm-hash sha256:98ebc15e78183261ab2d2405a404baeb4648ff08a9178473dfe05543f182d868 \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` ### Add rates to an existing card Rates are append-only. To change a price, add a rate from a later `starting_at`: ```bash metro ratecard add-rates preflight --rate-card-id=00000000-0000-4000-8000-000000000103 \ --file=rates.yaml --sandbox --out=plans/rates.json ``` It refuses any rate that already exists. Apply it the same way. ### Dimensional rate cards To price one usage product by a dimension, such as an action code, start from a plan and check it offline: ```bash metro plan add-pricing-dimension-value --action-code FEATURE_X --display-name "Feature X" --price 100 --sandbox --json metro validate --shape dimensional-rate-card --file dimension.json --json metro rate-card dimensional preview --file dimension.json --sandbox --json ``` The shape requires one USAGE product, a compound group key on the billable metric, `FLAT` rates with `entitled: true`, and a verified group key. Apply through the shape is blocked in this release; add the new rates with `metro ratecard add-rates`. To roll one value across several cards, run `metro plan rollout-dimension-across-cards --sandbox --json` after `metro catalog bind`. ## Readback metro checks the card's name and aliases, then finds every rate through `getRates`: ```text Applied (sandbox). Read-back (expected vs actual): ok rate_card.name: expected "Acme Standard" actual "Acme Standard" ok rate_card.aliases: expected ["acme_standard"] actual ["acme_standard"] ok rate 00000000-0000-4000-8000-000000000010@2026-12-01T00:00:00.000Z: expected {"entitled":true,"rate_type":"SUBSCRIPTION","price":4900} actual {...same...} ok rate 00000000-0000-4000-8000-000000000011@2026-12-01T00:00:00.000Z: expected {"entitled":true,"rate_type":"FLAT","price":2} actual {...same...} ``` Sample output is from metro's test suite; IDs are placeholders. Next: put the card in a [package](/docs/guides/provision-a-package). --- # Subscriptions and seats > Add subscriptions and change quantities or seats on a contract. Source: https://metrocli.com/docs/guides/subscriptions-and-seats/ · Docs index: https://metrocli.com/llms.txt ## Goal Give Acme Corp 10 monthly seats from 1 December 2026, then raise them to 12 from 1 January 2027. See [Subscriptions & seats](/docs/concepts/subscriptions-and-seats). ## Preview Add the subscription: ```bash metro subscription add preflight --ingest-alias=acme-corp \ --product-id=00000000-0000-4000-8000-000000000010 --billing-frequency=MONTHLY \ --quantity=10 --starting-at=2026-12-01T00:00:00.000Z --sandbox --out=plans/sub.json ``` ```text metro subscription add preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. contract 00000000-0000-4000-8000-000000000105.subscriptions: 0 -> 1 Steps: POST /v2/contracts/edit Payload hash: sha256:... ``` The dry run shows the `add_subscriptions` body metro will send: ```json {"customer_id":"00000000-0000-4000-8000-000000000101","contract_id":"00000000-0000-4000-8000-000000000105", "add_subscriptions":[{"subscription_rate":{"product_id":"00000000-0000-4000-8000-000000000010","billing_frequency":"MONTHLY"}, "collection_schedule":"ADVANCE","proration":{"is_prorated":true,"invoice_behavior":"BILL_ON_NEXT_COLLECTION_DATE"}, "quantity_management_mode":"QUANTITY_ONLY","initial_quantity":10,"starting_at":"2026-12-01T00:00:00.000Z"}], "uniqueness_key":"metro-edit-9ab86777e09e8ede13fee5e3"} ``` Preflight refuses when the product isn't a `SUBSCRIPTION` product, when the contract's rate card has no entitled `SUBSCRIPTION` rate for it at that frequency, or when the contract already has that subscription (pass `--allow-duplicate` to add it anyway). If the customer has more than one contract, pass `--contract-id=`. For a seat-based subscription, or any field the flags don't cover, pass a full spec with `--file=subscription.yaml`. Your Metronome account needs contract editing enabled. Then the quantity change: ```bash metro subscription set-quantity preflight --ingest-alias=acme-corp \ --subscription-id=00000000-0000-4000-8000-000000000106 --quantity=12 \ --starting-at=2027-01-01T00:00:00.000Z --sandbox --out=plans/qty.json ``` ```text subscription 00000000-0000-4000-8000-000000000106 quantity @ 2027-01-01T00:00:00.000Z: 10 -> 12 Steps: POST /v2/contracts/edit ``` `--delta=2` works too. metro always sends an absolute `quantity`, computed from the current schedule, so apply writes exactly what you previewed. ### Seats For a `SEAT_BASED` subscription, change seats instead of quantity: ```bash metro subscription seats preflight --ingest-alias=acme-corp \ --subscription-id=00000000-0000-4000-8000-000000000106 \ --starting-at=2027-01-01T00:00:00.000Z --add-seat-ids=user-41,user-42 --sandbox ``` `--remove-seat-ids=`, `--add-unassigned=` and `--remove-unassigned=` work the same way. ## Confirm Show the human the contract, the product, the quantity before and after, and the hash. Increases are prorated onto the next invoice by default; decreases take effect at the next billing boundary. Then dry-run: ```bash metro subscription set-quantity apply --file plans/qty.json --sandbox --confirm-hash sha256:... ``` ## Apply ```bash metro subscription add apply --file plans/sub.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX metro subscription set-quantity apply --file plans/qty.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` ## Readback ```text Applied (sandbox). Read-back (expected vs actual): ok quantity at 2027-01-01T00:00:00.000Z: expected 12 actual 12 ``` `subscription add` checks the subscription count for that product and frequency, and the quantity at its start. `subscription seats` reads the seats history and checks the assigned seat IDs; it checks the total only when you change unassigned seats alone, because assigned seats fill unassigned ones first. A failed readback looks like this and exits `3`: ```text Applied, but read-back FAILED (sandbox). Read-back (expected vs actual): FAIL quantity at 2027-02-01T00:00:00.000Z: expected 15 actual 12 ``` Don't re-run the plan. Read the contract fresh with `metro ops who "Acme Corp" --sandbox`, find the cause, then preflight again. --- # Credits and commits > Complimentary grants, paid top-ups and ledger adjustments. Source: https://metrocli.com/docs/guides/credits-and-commits/ · Docs index: https://metrocli.com/llms.txt ## Goal Three common balance changes on Acme Corp's active contract: | Change | Command | Metronome call | |---|---|---| | Add or remove an amount on an existing balance | `metro ledger-adjustment preflight --amount=` | manual ledger entry | | Grant a new credit, or a complimentary commit | `metro ledger-adjustment preflight --grant=credit` or `--grant=commit` | contract edit, `add_credits` or `add_commits` | | Remove a whole grant | `metro ledger-adjustment preflight --archive-balance-id=` | contract edit, archive | Every write carries a `uniqueness_key`, so a retry returns `409` instead of a second grant. See [Credits & commits](/docs/concepts/credits-and-commits). ## Preview First, read the balances: ```bash metro customer balances --ingest-alias=acme-corp --sandbox --only-nonzero --json ``` The output includes `spendableNet`: the net balance per credit type next to the sum of the balance list. If they disagree, metro warns with `MTR-CREDIT-NET-001` and refuses additions for that credit type. Trust the net. Then preflight the change. A $500 service credit for one year, as a new grant on a USD-cents credit type: ```bash metro ledger-adjustment preflight --grant=credit --amount=50000 \ --product-id=00000000-0000-4000-8000-000000000011 \ --starting-at=2026-12-01T00:00:00.000Z --ending-before=2027-12-01T00:00:00.000Z \ --reason="Service credit for the November outage" \ --ingest-alias=acme-corp --sandbox --out=ledger.json ``` The credit type comes from `metro catalog bind --sandbox --write`, or pass `--credit-type-id=`; metro won't guess it. The amount is in that credit type's units. Name the grant with `--grant-name=`, and set `--priority=` to control drawdown order. `--grant=commit` adds a `PREPAID` commit with no invoice schedule: a complimentary commit. Or an adjustment of an existing balance. Additions need a target: `--contract-id=` or `--balance-id=`. A removal picks the one balance that covers it, or asks you to choose. ```bash metro ledger-adjustment preflight --amount=-2500 --reason="Correct double grant" \ --ingest-alias=acme-corp --balance-id=00000000-0000-4000-8000-000000000008 \ --sandbox --out=ledger.json ``` The preflight prints the diff, for example `balance 00000000-0000-4000-8000-000000000008: 10000 -> 7500`, the steps and the `Payload hash`. ### Offline first, if you want The `complimentary-credit-grant` and `paid-credit-top-up` shapes check a grant with no API call at all. This is real output: ```bash metro plan template complimentary-credits --sandbox --out credit.json metro validate --shape complimentary-credit-grant --file credit.json metro credit preview --shape complimentary-credit-grant --file credit.json --sandbox ``` ```text ✓ Validation passed for complimentary-credit-grant. Why: The input matches the reviewed shape rules and guardrails. Preview built for complimentary-credit-grant on sandbox. Payload hash: sha256:d96a502b2c89d69048dfd7aff170ea47e1b0af9f71e2c57905bf6718b8f43f6e Actions: 1 Apply supported: no ``` Shapes don't apply. Use them to agree on the grant, then run the ledger-adjustment preflight above. ## Confirm Show the human the customer, the balance before and after (or the new grant's amount and dates), the reason and the hash. Then dry-run: ```bash metro ledger-adjustment apply --file ledger.json --sandbox --confirm-hash sha256:... ``` ## Apply ```bash metro mode write metro ledger-adjustment apply --file ledger.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` On production: `--prod --confirm-prod-apply=I_UNDERSTAND_BILLING_SIDE_EFFECTS`, after the human's typed yes for this change. ## Readback metro re-reads the balances. The check depends on the mode: ```text Applied (sandbox). Read-back (expected vs actual): ok balance 00000000-0000-4000-8000-000000000008: expected 7500 actual 7500 ``` A grant checks `add_credits present with amount 50000` (or `add_commits`). An archive checks ` archived`. Any `FAIL` exits `3`. Illustrative IDs; the format is exact. --- # Clone a package version > Publish a new package version behind the same aliases at a handoff hour. Source: https://metrocli.com/docs/guides/clone-a-package-version/ · Docs index: https://metrocli.com/llms.txt ## Goal Publish a new version of the `growth` package that takes over the alias at 1 January 2027, 00:00 UTC, and switch its usage statements to the contract anniversary. Contracts created from that hour get the new version. Existing contracts keep the version they were created from. Packages can't be edited, so a new version is a fresh package create whose alias entry starts at the handoff. From that hour, alias resolution moves to the new version. See [Packages](/docs/concepts/packages). ## Preview ```bash metro package list --search=growth --sandbox --json metro package clone-version preflight --aliases=growth --handoff-at=2027-01-01T00:00:00.000Z \ --usage-day=CONTRACT_START --sandbox --out=plans/clone.json ``` `--aliases` takes a comma-separated list, so one plan can roll several packages at once. For each alias, preflight: - reads the version live now and copies it into a new create body; - sets the alias on the new version to start at `--handoff-at`, which must be a future UTC hour; - changes `usage_statement_schedule.day` only if you pass `--usage-day` (`CONTRACT_START` or `FIRST_OF_MONTH`); - bumps the `uniqueness_key`, and skips an alias whose new key already exists, so a re-run creates nothing twice. It blocks with `alias_not_live` when no version is live, and with `alias_already_has_a_future_version` when a handoff is already scheduled. The diff shows, per alias: ```text growth.usage_statement_schedule.day: "FIRST_OF_MONTH" -> "CONTRACT_START" growth.resolves_to: "00000000-0000-4000-8000-000000000104" -> "(new version) from 2027-01-01T00:00:00.000Z" Steps: POST /v1/packages/create Payload hash: sha256:... ``` To change prices or terms in the new version, write a full spec instead and run `metro package create preflight --file=package.yaml --allow-alias-takeover --sandbox`, with a future `starting_at` on the alias. Preflight warns `MTR-PKG-004` that the alias moves. ## Confirm Show the human each alias, the handoff hour, what changes, and the hash. Check who's on the old version with `metro package customers --alias=growth --sandbox`. Then dry-run: ```bash metro package clone-version apply --file plans/clone.json --sandbox --confirm-hash sha256:... ``` ## Apply ```bash metro package clone-version apply --file plans/clone.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` Nothing is archived. When you later retire the old version, check it offline first: `metro package archive preview --file handoff.json --sandbox` refuses an archive until the replacement alias is live and read back. Archiving before then makes contract creation fail with `400`. ## Readback metro reads the new package back, compares it with the plan, and proves both sides of the handoff: ```text Applied (sandbox). Read-back (expected vs actual): ok growth.name: expected "Acme Growth" actual "Acme Growth" ok growth.rate_card_id: expected "00000000-0000-4000-8000-000000000103" actual "00000000-0000-4000-8000-000000000103" ok growth.usage_day: expected "CONTRACT_START" actual "CONTRACT_START" ok growth.alias_starting_at: expected "2027-01-01T00:00:00.000Z" actual "2027-01-01T00:00:00.000Z" ... ok growth resolves to predecessor before handoff: expected "00000000-0000-4000-8000-000000000104" actual "00000000-0000-4000-8000-000000000104" ok growth resolves to new version at handoff: expected "00000000-0000-4000-8000-000000000204" actual "00000000-0000-4000-8000-000000000204" ``` The full list also covers the uniqueness key, duration, usage frequency, billing provider, and subscription, credit and commit counts. Illustrative IDs; the check names are exact. Any `FAIL` exits `3`. --- # Invoices > Update an invoice issue date, with the Stripe expectations reviewed first. Source: https://metrocli.com/docs/guides/invoices/ · Docs index: https://metrocli.com/llms.txt ## Goal Move a draft invoice's issue date from 1 December to 5 December 2026, without surprising the customer in Stripe. Metronome changes an issue date through `POST /v1/contracts/updateInvoiceIssueDate`. It works only on `DRAFT` invoices, and the new date must come before the contract's end. See [Invoices](/docs/concepts/invoices). > **Preview only in this release.** metro validates and previews this change, and builds the guarded read for the readback. It does not apply it yet: the endpoint isn't on the sandbox write allowlist, and the shape's apply mode is blocked. Make the change where your team makes it today, then read it back with metro. ## Preview Write the input. Every field is required, and the evidence flags say what you've already checked. ```json { "customerId": "00000000-0000-4000-8000-000000000001", "contractId": "00000000-0000-4000-8000-000000000002", "invoiceId": "00000000-0000-4000-8000-000000000003", "currentInvoiceStatus": "DRAFT", "currentIssueDate": "2026-12-01T00:00:00.000Z", "targetIssueDate": "2026-12-05T00:00:00.000Z", "contractHasNoEndDate": true, "invoiceReadbackVerified": true, "contractEndVerified": true, "billingProvider": { "verified": true }, "stripeBehavior": "remain_draft_for_manual_review", "verificationPlan": { "invoiceReadback": true, "billingProviderReadback": true, "stripeDeliveryReview": true }, "remediationPlan": "Move the issue date back with the same endpoint while the invoice is still DRAFT." } ``` ```bash metro validate --shape invoice-issue-date-update --file issue-date.json metro invoice issue-date preview --file issue-date.json --sandbox ``` ```text ✓ Validation passed for invoice-issue-date-update. Why: The input matches the reviewed shape rules and guardrails. Preview built for invoice-issue-date-update on sandbox. Payload hash: sha256:9e12f2fc713df1919e5f862a4d0f5ad8a5352f1d94626583a0431a4c02712b6c Actions: 1 Apply supported: no ``` `stripeBehavior` must be one of `defer_until_new_issue_date`, `remain_draft_for_manual_review` or `no_stripe_delivery_expected`. Anything else fails with `MTR-INV-004`. That's the point of the shape: you decide what Stripe should see before anything moves. ## Confirm Show the human the invoice, the old and new issue dates, the Stripe behavior and the hash. Check the remediation plan reads as something you could actually do. A finalized invoice can't be moved, so confirm the status is still `DRAFT` on the day. ## Apply Not in metro yet. Make the change in Metronome, with the reviewed preview as the change record. When metro ships apply for this shape, this step becomes the same `--confirm-hash` and `--apply` pair as every other guide. ## Readback Read the invoice back through the guarded read chain. `invoices.get` is on the live read allowlist. ```bash metro invoice inspect --invoice-id 00000000-0000-4000-8000-000000000003 --sandbox --plan echo '{"invoice_id":"00000000-0000-4000-8000-000000000003"}' > get-invoice.json metro api read-plan invoices.get --file get-invoice.json --sandbox --json > read-plan.json metro api read-gate template --read-plan read-plan.json --json > read-gate.json # fill in and review the gate: status, tenant profile, key env and fingerprint metro api read-gate validate --file read-gate.json metro api read invoices.get --file get-invoice.json --sandbox --read-gate read-gate.json \ --confirm-live-read I_UNDERSTAND_THIS_WILL_READ_LIVE_METRONOME --json ``` Compare expected and actual yourself, and report both: | Field | Expected | Actual | |---|---|---| | status | `DRAFT` | from the read | | issue date | `2026-12-05T00:00:00.000Z` | from the read | | Stripe invoice | per `stripeBehavior` | from your billing provider | --- # Move a customer between plans > Move-plan preflight, then apply, one customer or in bulk. Source: https://metrocli.com/docs/guides/move-a-customer/ · Docs index: https://metrocli.com/llms.txt ## Goal Move Acme Corp from its current package to `growth` at its next renewal boundary, without an unplanned invoice. A move is two writes: `updateEndDate` on the current contract at the cutover, then a successor contract on the target package with a `RENEWAL` transition from the old one. Balances carry over by each grant's `rollover_fraction`. See [Contracts](/docs/concepts/contracts). ## Preview ```bash metro contract move-plan preflight --to=growth --ingest-alias=acme-corp \ --cutover-mode=renewal-boundary --sandbox --out=move.json ``` The cutover is one of: | Flag | Cutover | |---|---| | `--cutover-mode=renewal-boundary` (default) | The next monthly boundary after the last paid plan invoice, or the contract start | | `--cutover-mode=next-hour` | The next UTC hour | | `--cutover-mode=current-hour` | The current UTC hour. May finalize the plan fee immediately. | | `--cutover=` | An exact UTC hour | Pass `--from=` to assert which package the customer is on now. Preflight then stops if the current package doesn't carry that alias. ```text metro contract move-plan preflight (sandbox, key sha256:80f0714120b8) - read-only, nothing written to Metronome. contract 00000000-0000-4000-8000-000000000002.ending_before: null -> "2027-01-01T00:00:00.000Z" successor contract: null -> {"package_id":"00000000-0000-4000-8000-000000000104","alias":"growth","starting_at":"2027-01-01T00:00:00.000Z","transition":"RENEWAL"} Steps: POST /v1/contracts/updateEndDate ; POST /v1/contracts/create Payload hash: sha256:... ``` Preflight needs one active contract to move from: the single open-ended one, or the only active one. An active trial qualifies with warning `MTR-MOVE-TRIAL-001`, because apply truncates it at the cutover. An expired customer doesn't; create a fresh contract instead. Preflight pins the target package live at the cutover, warns about balances that won't roll over, and warns `MTR-TIME-002` when the cutover isn't in the future. > **Credits on the new plan.** move-plan no longer takes a target credit amount. Grant credits on the successor afterwards with `metro ledger-adjustment preflight --grant=credit`, through the same ladder. See [Credits and commits](/docs/guides/credits-and-commits). ## Confirm Show the human the cutover hour, the old contract's new end, the target package, any rollover warning and the hash. Then dry-run: ```bash metro contract move-plan apply --file move.json --sandbox --confirm-hash sha256:... ``` ## Apply ```bash metro contract move-plan apply --file move.json --sandbox --confirm-hash sha256:... \ --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` ### In bulk Write a roster: one customer ID per line. Lines starting with `#`, and a `customer_id` header, are skipped. ```bash metro contract move-plan bulk-preflight --to=growth --roster-file=roster.csv \ --cutover-mode=renewal-boundary --sandbox --out-dir=plans/bulk-move ``` ```text Planned 40/40 moves (0 failed). Manifest: plans/bulk-move/manifest.json Manifest hash: sha256:... Canary: metro contract move-plan bulk-apply --file plans/bulk-move/manifest.json --sandbox --confirm-hash sha256:... --limit=1 --apply --confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX ``` Run the canary line first: `--limit=1` moves one customer. Read it back, then run the same command without `--limit`. bulk-apply stops at the first failure, waits `--delay-ms` (default 300) between moves, and refuses a manifest edited after preflight. ## Readback ```text Applied (sandbox). Read-back (expected vs actual): ok predecessor.ending_before: expected "2027-01-01T00:00:00.000Z" actual "2027-01-01T00:00:00.000Z" ok successor exists: expected true actual true ok successor.starting_at: expected "2027-01-01T00:00:00.000Z" actual "2027-01-01T00:00:00.000Z" ok successor.package_id: expected "00000000-0000-4000-8000-000000000104" actual "00000000-0000-4000-8000-000000000104" ok alias growth resolves to successor package at cutover: expected "00000000-0000-4000-8000-000000000104" actual "00000000-0000-4000-8000-000000000104" ``` Illustrative IDs; the check names are exact. Any `FAIL` exits `3`. Confirm from the customer's side with `metro ops who "Acme Corp" --sandbox`. --- # Metronome architecture primer > Customer, contract, package, rate card, product and billable metric, with credits, commits and invoices. Source: https://metrocli.com/docs/concepts/architecture/ · Docs index: https://metrocli.com/llms.txt Metronome turns usage into invoices. Data flows one way: usage events become billable quantities, rate cards price them, a contract ties one customer to those prices, and each billing period ends in an invoice. > **Metronome's reference:** [How Metronome invoices work](https://docs.metronome.com/guides/implement-metronome/core-concepts/how-invoicing-works) · [Create a contract](https://docs.metronome.com/api-reference/contracts/create-a-contract) · [Create a package](https://docs.metronome.com/api-reference/contracts/create-a-package) · [docs.metronome.com/llms.txt](https://docs.metronome.com/llms.txt). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). | Object | What it is | metro command | |---|---|---| | Customer | The account you bill. Events reach it through ingest aliases. | `metro customer create` | | Billable metric | Filters and aggregates usage events into a quantity. | `metro usage ingest preview` | | Product | One invoice line. Has no price of its own. | `metro product inspect` | | Rate card | Prices for products, effective from a start date. | `metro ratecard create` | | Package | A reusable contract template behind an alias. Never edited, only versioned. | `metro package create` | | Contract | Connects one customer to pricing, balances and subscriptions. | `metro contract create` | | Credits & commits | Balances that usage draws down. | `metro ledger-adjustment` | | Subscriptions & seats | Recurring charges. Quantity is usually seats. | `metro subscription add` | | Invoice | Built each period from usage, rates and contract terms. | `metro invoice issue-date preview` | ## How the IDs connect | Object | Points at | Pointed at by | |---|---|---| | Customer | billing provider configs | usage events (`customer_id` or an ingest alias), contracts | | Billable metric | usage events, by `event_type` and property filters | USAGE products (`billable_metric_id`) | | Product | a billable metric (USAGE only) | rates, commits, credits, overrides | | Rate card | products (`product_id` on each rate) | packages and direct contracts (`rate_card_id`) | | Package | a rate card | contracts (`package_alias` or `package_id`) | | Contract | a customer, plus a package or a rate card | invoices, transitions, hierarchy children | | Commit or credit | a contract and a product | invoice lines (`commit_purchase`, `applied_commit_or_credit`) | | Subscription | a SUBSCRIPTION product on the contract's rate card | seat history | | Invoice | a customer and a contract | the billing provider's invoice (`external_invoice.id`) | ## Four facts that shape every change 1. **Packages and rate-card rates are append-only.** You never edit a package; you publish a new version behind the same alias. You never edit a rate; you add a new one from a later `starting_at`. 2. **Time is on the hour.** `starting_at`, `ending_before` and schedule timestamps must be exactly `:00:00Z`, or Metronome returns `400`. 3. **Money is in cents.** A $250 charge is `25000`. There is no "never expires" flag; the convention is an `ending_before` about 100 years out. 4. **One base URL, two tenants.** Sandbox and production both call `https://api.metronome.com`. The key decides the tenant, which is why metro makes you name it on every call. ## Which metro command touches what | Object | Read | Write | |---|---|---| | Customer | `metro ops who`, `metro customer resolve` | `metro customer create` | | Rate card | `metro catalog bind` | `metro ratecard create`, `metro ratecard add-rates` | | Package | `metro package list`, `metro package customers` | `metro package create`, `metro package clone-version` | | Contract | `metro ops who` | `metro contract create`, `metro contract move-plan`, `metro contract extend-trial`, `metro contract expire` | | Credits and commits | `metro customer balances` | `metro ledger-adjustment` | | Subscriptions and seats | `metro ops who` | `metro subscription add`, `metro subscription set-quantity`, `metro subscription seats` | | Invoice | `metro invoice inspect --plan` | `metro invoice issue-date preview` (preview only) | Each object has its own page in this section, with its gotchas. Metronome's docs at [docs.metronome.com](https://docs.metronome.com) are the source of truth; when this page and theirs disagree, theirs wins. --- # Customers > Customers, ingest aliases and how lookups work. Source: https://metrocli.com/docs/concepts/customers/ · Docs index: https://metrocli.com/llms.txt A customer is the Metronome record for the account you bill. It has a stable Metronome UUID, a name, ingest aliases, custom fields, and billing provider configurations. > **Metronome's reference:** [Create a customer](https://docs.metronome.com/api-reference/customers/create-a-customer) · [List customers](https://docs.metronome.com/api-reference/customers/list-customers) · [Create or update customer ingest aliases](https://docs.metronome.com/api-reference/customers/create-or-update-customer-ingest-aliases) · [Archive a customer](https://docs.metronome.com/api-reference/customers/archive-a-customer) · [Set custom field values](https://docs.metronome.com/api-reference/custom-fields/set-custom-field-values). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## How it connects - **Usage events** reach a customer through `customer_id`, which can be the Metronome ID or any of its **ingest aliases**, for example `acme-corp`. - **Contracts** reference `customer_id`. - **Billing provider configs** (for example Stripe) attach to the customer. Contracts inherit them unless a contract sets its own. - **Hierarchies** are declared on the child's contract, not on the customer: the child contract points at the parent's `customer_id` and `contract_id`. ## Gotchas - Ingest aliases must be unique across the tenant. A collision returns `409` with `conflicting_id`. - Setting ingest aliases replaces the whole list. An alias you leave out is removed. - Archiving a customer archives all of its contracts and voids its finalized invoices. It does not refund Stripe. - Archived customers keep their ingest aliases until you set an empty list on them. - Custom field keys must be allowlisted per entity before use. One unknown key fails the whole write, and each value is limited to 200 characters. - A hierarchy holds at most 10 nodes: one parent and nine children. - `POST /v1/customers` takes no `uniqueness_key`. ## How metro handles it - **Lookups.** `metro ops who`, `metro customer resolve` and every op take one of `--customer-id=`, `--external-id=`, `--ingest-alias=` or `--name=`. Metronome has no server-side name filter, so a name lookup stops at the first exact match; an email-shaped name routes through the ingest alias in one call. Pass an ID when uniqueness matters. - **Create.** `metro customer create preflight --name=... --ingest-alias=...` makes the aliases the idempotency anchor. It needs at least one, refuses any alias that belongs to an active or archived customer, and checks again just before writing, so the same plan can't create two customers. See [Provision a package](/docs/guides/provision-a-package). - **External IDs.** `--external-id=` writes into the custom field named by `--external-id-field`, which defaults to the first key in `METRO_EXTERNAL_ID_FIELDS`, or `external_id`. | Command | Does | |---|---| | `metro ops who "Acme Corp" --sandbox` | Customer, active contracts and nonzero balances | | `metro customer resolve --ingest-alias=acme-corp --sandbox --json` | Resolve one customer | | `metro customer create preflight` / `apply` | Create a customer with aliases, custom fields and optional Stripe config | | `metro customer setup preview --file customer.json --sandbox` | Offline preview of the `customer-setup` shape | Metronome docs: [Create a customer](https://docs.metronome.com/api-reference/customers/create-a-customer). --- # Billable metrics > Usage events, aggregations and group keys. Source: https://metrocli.com/docs/concepts/billable-metrics/ · Docs index: https://metrocli.com/llms.txt A **usage event** is a raw record of what a customer did, in a schema you design, sent to `/v1/ingest`. A **billable metric** reads that stream and turns matching events into a quantity. > **Metronome's reference:** [Ingest events](https://docs.metronome.com/api-reference/usage/ingest-events) · [Create a billable metric](https://docs.metronome.com/api-reference/billable-metrics/create-a-billable-metric) · [List all billable metrics](https://docs.metronome.com/api-reference/billable-metrics/list-all-billable-metrics). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## Usage events | Field | Required | Notes | |---|---|---| | `customer_id` | yes | The Metronome ID or an ingest alias | | `event_type` | yes | What happened, for example `api_call` | | `timestamp` | yes | RFC 3339, UTC | | `transaction_id` | yes | Up to 128 characters. Deduplicates retries. | | `properties` | no | Anything a metric filters, sums or groups on | ## Billable metrics A metric matches on `event_type` plus property filters, then aggregates: `COUNT`, `SUM`, `MAX`, `UNIQUE` or `LATEST`. `SUM`, `MAX`, `UNIQUE` and `LATEST` need an `aggregation_key`. **Group keys** split the quantity, for invoice breakouts or for dimensional pricing. A USAGE [product](/docs/concepts/products) references exactly one metric through `billable_metric_id`. ## Gotchas - Events older than 34 days are dropped. For older periods, Metronome uses historical invoices instead. - A request carries at most 100 events, as a JSON array even for one. A schema error in any event rejects the whole batch. - Replaying the same `transaction_id` inside 34 days does nothing, so retries are safe. Never generate a new ID on each retry. - Metrics aren't retroactive. Events ingested before a metric existed aren't counted by it. - Renaming an `event_type` that a live metric filters on silently orphans future events. - After creation only the name can change. A different aggregation means a new metric. - Past-dated events inside the 34-day window can still change open draft invoices and commit burn-down. - For dimensional pricing with a code and a display name, the metric needs one compound group key holding both, for example `[["action_code", "action_display_name"]]`. Separate keys fail validation. ## How metro handles it | Command | Does | |---|---| | `metro usage ingest preview --file events.json --sandbox` | Offline check of an event batch, `usage-ingest-preview` shape | | `metro catalog bind --sandbox --write` | Finds your billable metric and saves its ID | | `metro plan greenfield-credits-product --sandbox --json` | Plans a new metric and USAGE product, preview only | | `metro docs explain credits.product.decision --markdown` | Decides whether you need a new metric at all | Metronome docs: [Create a billable metric](https://docs.metronome.com/api-reference/billable-metrics/create-a-billable-metric). --- # Products > Usage, fixed and subscription products, and how they map to rates. Source: https://metrocli.com/docs/concepts/products/ · Docs index: https://metrocli.com/llms.txt A product is one line item on an invoice. Its name is what your customer sees. A product has no price of its own: prices live on [rate cards](/docs/concepts/rate-cards). > **Metronome's reference:** [Create a product](https://docs.metronome.com/api-reference/products/create-a-product) · [Update a product](https://docs.metronome.com/api-reference/products/update-a-product) · [Archive a product](https://docs.metronome.com/api-reference/products/archive-a-product). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## Types | Type | What it bills | Needs | |---|---|---| | `USAGE` | A billable metric's quantity | `billable_metric_id` | | `SUBSCRIPTION` | A recurring charge per unit, usually seats | A `SUBSCRIPTION` rate with `billing_frequency` | | `FIXED` | A one-off or scheduled amount | Priced on the commit or scheduled charge that uses it | | `COMPOSITE` | A percentage of other products | `composite_product_ids` or `composite_tags` | | `PROFESSIONAL_SERVICE` | Services | Enabled per tenant | ## How it connects Rates reference `product_id`. Commits, credits, scheduled charges and overrides reference `product_id`, or match product tags through `applicable_product_tags`. ## Gotchas - A product's `type` can't change. To switch, archive it, create a new one, and re-point everything that used it. - Updates are scheduled at an on-the-hour `starting_at`. Updating `tags` replaces the list. - `products/get` returns `data.current` and `data.initial`; there is no top-level `data.name`. - Archiving a product only blocks new rates. Existing entitled rates keep billing, and there is no remove-rate endpoint. Close rates with `entitled: false` first. - Metronome doesn't stop two entitled products on one rate card from using the same metric. If that happens, every event bills twice. ## How metro handles it | Command | Does | |---|---| | `metro product inspect --product-id --sandbox --plan` | A read plan for one product | | `metro product retire preview --file retire.json --sandbox` | Offline preview that closes rates with `entitled: false` and `price: 0` before any archive | | `metro ratecard create preflight` | Checks every product exists, isn't archived, and that a `SUBSCRIPTION` rate points at a `SUBSCRIPTION` product | Metronome docs: [Create a product](https://docs.metronome.com/api-reference/products/create-a-product). --- # Rate cards > Rates, effective dates, rate types and dimensional rate cards. Source: https://metrocli.com/docs/concepts/rate-cards/ · Docs index: https://metrocli.com/llms.txt A rate card is a catalog of prices. Each rate is one entry for a (product, `starting_at`) pair. Rates are time-sliced and append-only: adding a rate schedules a change from its start date, and never edits a rate in place. One rate card can serve many packages and contracts. > **Metronome's reference:** [Create a rate card](https://docs.metronome.com/api-reference/rate-cards/create-a-rate-card) · [Add rates](https://docs.metronome.com/api-reference/rate-cards/add-rates) · [Get rates](https://docs.metronome.com/api-reference/rate-cards/get-rates) · [Get a rate schedule](https://docs.metronome.com/api-reference/rate-cards/get-a-rate-schedule). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## How it connects - Each rate references `product_id` and a `credit_type_id` (fiat, or a custom credit type). - [Packages](/docs/concepts/packages) and direct [contracts](/docs/concepts/contracts) reference `rate_card_id`. - A contract can override its rate card's prices without touching the card. ## Rate types Each rate has exactly one type. | Type | Price | |---|---| | `FLAT` | An integer price per unit | | `PERCENTAGE` | A fraction from 0 to 1, usually on a `COMPOSITE` product | | `TIERED` | A list of tiers, bucketed by default | | `SUBSCRIPTION` | A price per unit per period. Needs `billing_frequency`. | | `CUSTOM` | A free-form rate, enabled per tenant | A rate can also carry a `commit_rate`: a different price while a commit or credit is drawn down. ## Dimensional rate cards A USAGE product can split pricing by event properties. `pricing_group_key` names the properties, for example `["region"]`, and each rate targets one combination with `pricing_group_values`, for example `region: us-east-1`. `presentation_group_key` splits how lines display without splitting the price. New action codes are new rates on one USAGE product, not new products. The billable metric needs one compound group key holding both the code and its display name. ## Gotchas - Use `addRates`, at most 100 rates per call. The single-rate endpoint is heavily rate-limited. - Adding a rate with the same product and `starting_at` replaces the rate at that time. Earlier rates stay as history. - `starting_at` must be a UTC hour boundary. A past hour can finalize invoice lines right away. - A contract's rate card can't be swapped. A different card means a new contract. - `getRates` returns the card's prices. A customer with overrides needs the contract's rate schedule instead. - Pricing in a custom credit type collapses usage into one "Credits conversion" line on Stripe invoices. - A new card silently takes an alias from the card that holds it. ## How metro handles it | Command | Does | |---|---| | `metro ratecard create preflight --file=ratecard.yaml --sandbox` | Create a card and its rates. Refuses a name that exists, and an alias held by another card unless `--allow-alias-move`. | | `metro ratecard add-rates preflight --rate-card-id= --file=rates.yaml --sandbox` | Add rates to an existing card. Refuses a rate that already exists. | | `metro rate-card dimensional preview --file input.json --sandbox` | Offline preview of the `dimensional-rate-card` shape | | `metro plan add-pricing-dimension-value --sandbox --json` | Plans one new dimension value | See [Plans and rate cards](/docs/guides/plans-and-rate-cards). Metronome docs: [Add rates](https://docs.metronome.com/api-reference/rate-cards/add-rates). --- # Packages > Reusable contract templates, aliases and versions. Source: https://metrocli.com/docs/concepts/packages/ · Docs index: https://metrocli.com/llms.txt A package is a reusable, customer-agnostic contract template. It bundles a rate card, a duration, billing settings, and optionally recurring commits, credits and subscriptions. A contract created from a package copies the template at creation time. > **Metronome's reference:** [Create a package](https://docs.metronome.com/api-reference/contracts/create-a-package) · [Get a package](https://docs.metronome.com/api-reference/packages/get-a-package) · [List all packages](https://docs.metronome.com/api-reference/list-all-packages) · [Archive a package](https://docs.metronome.com/api-reference/packages/archive-a-package) · [List contracts associated with a package](https://docs.metronome.com/api-reference/contracts/list-contracts-associated-with-a-package). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## Aliases and versions Packages can't be edited. To change one, you publish a new package with the same alias and a future `starting_at` on that alias. From that hour the alias resolves to the new version. Existing contracts keep the version they were created from. An alias resolves to the version live at the **contract's** `starting_at`, not at the time of the call. Use aliases, not hardcoded package IDs. ## How it connects A package references a rate card. Contracts reference it through `package_alias` or `package_id`. Listing the contracts on a package shows who uses it. ## Gotchas - Aliases must be objects, `[{ "name": "growth" }]`. A plain string alias is silently ignored. - Recurring commits on a package need `starting_at_offset` and `proration`, which direct contracts don't. A missing one gives an unhelpful schema error. - Don't archive an old version until the new alias is live. In that gap, contract creation fails with `400`. - Package list returns archived packages too, and returns `uniqueness_key` with a `package:` prefix. - A tenant holds at most 75 active packages, plus archived ones that still have contracts. - A package with a seat subscription needs a matching subscription rate on its rate card. - Annual packages should set `usage_statement_schedule.day: CONTRACT_START`. The default is `FIRST_OF_MONTH`. ## How metro handles it | Command | Does | |---|---| | `metro package list --sandbox --json` | All packages, with `--search=`, `--only-active`, `--only-archived` | | `metro package customers --alias=growth --sandbox` | Contracts created from a package | | `metro package create preflight --file=package.yaml --sandbox` | Create a package. Derives a `uniqueness_key` if you don't pass one, and refuses an alias another package holds. | | `metro package clone-version preflight --aliases=growth --handoff-at= --sandbox` | Publish a new version behind the same alias. Nothing is archived. | | `metro package archive preview --file handoff.json --sandbox` | Offline check that refuses archive until the new alias is live | See [Clone a package version](/docs/guides/clone-a-package-version). Metronome docs: [Create a package](https://docs.metronome.com/api-reference/contracts/create-a-package). --- # Contracts > Contracts from packages or direct, transitions, overrides and end dates. Source: https://metrocli.com/docs/concepts/contracts/ · Docs index: https://metrocli.com/llms.txt A contract is a customer's billing agreement. It connects one customer to pricing: a package, or a rate card with its own terms. It holds commits, credits, overrides, scheduled charges and subscriptions, and it produces invoices. > **Metronome's reference:** [Create a contract](https://docs.metronome.com/api-reference/contracts/create-a-contract) · [Edit a contract](https://docs.metronome.com/api-reference/contracts/edit-a-contract) · [Update the contract end date](https://docs.metronome.com/api-reference/contracts/update-the-contract-end-date) · [Archive a contract](https://docs.metronome.com/api-reference/contracts/archive-a-contract) · [Manage subscription lifecycle](https://docs.metronome.com/guides/pricing-packaging/subscription/manage-subscription-lifecycle). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## Two ways to create one | From a package | Direct | |---|---| | `customer_id`, `starting_at`, `package_alias` or `package_id`, `uniqueness_key`, `transition`, `custom_fields`. Anything else returns `400`. | `rate_card_id` plus commits, subscriptions, billing provider and the other create fields | | Customize by editing after create | Customize at create | ## Changes after create All changes go through a contract edit, a few dedicated endpoints, or a transition to a new contract. - **Overrides** change prices for one customer: `OVERWRITE`, `MULTIPLIER` or `TIERED`. They can't be updated, only removed and re-added in the same edit. - **End dates** move with `updateEndDate`. - **Transitions** link a predecessor and a successor. `RENEWAL` hands off to a successor and carries over `balance × rollover_fraction`. On package contracts, the verified pattern is two steps: end the old contract, then create the successor with `RENEWAL`. `SUPERSEDE` returns `400` on package contracts. ## Gotchas - A contract edit is atomic: if one operation fails, nothing applies. Some edits return `200` and silently don't apply, so always read back. - A contract that was renewed or superseded and has finalized invoices can't be edited. - `updateEndDate` defaults `allow_ending_before_finalized_invoice` to `true`. Shortening a contract truncates draft statements and removes upcoming scheduled invoices. - Archiving a contract requires `void_invoices`. `true` voids every invoice, including paid ones, and Stripe is not refunded. - An expired contract's upgrade is a fresh create without a transition. - Two concurrent contracts bill twice. ## How metro handles it | Command | Does | |---|---| | `metro contract create preflight --package-alias=growth --starting-at= --ingest-alias=acme-corp --sandbox` | Pins the package live at `starting_at`. Refuses an overlapping contract unless `--allow-concurrent`. | | `metro contract move-plan preflight --to=` | End the current contract, then a `RENEWAL` successor. Needs one active contract to move from. | | `metro contract extend-trial preflight --extend-by-days=` | Moves the end date out | | `metro contract expire preflight` | Moves the end date in. Always sends `allow_ending_before_finalized_invoice` explicitly: `false` unless you pass `--allow-ending-before-finalized-invoice`, and it's part of the hash. | | `metro contract repair-accidental preflight` | Archives a contract created by mistake and keeps the right one | | `metro contract inspect --contract-id --sandbox --plan` | A read plan for one contract | See [Create a contract](/docs/guides/create-a-contract) and [Move a customer](/docs/guides/move-a-customer). Metronome docs: [Create a contract](https://docs.metronome.com/api-reference/contracts/create-a-contract). --- # Credits & commits > Prepaid and postpaid commits, credits, access and invoice schedules, and the balance ledger. Source: https://metrocli.com/docs/concepts/credits-and-commits/ · Docs index: https://metrocli.com/llms.txt Credits and commits are both balances that usage draws down. > **Metronome's reference:** [Apply credits and commits to contracts](https://docs.metronome.com/pricing-packaging/apply-credits-commits) · [List balances](https://docs.metronome.com/api-reference/credits-and-commits/list-balances) · [Get the net balance of a customer](https://docs.metronome.com/api-reference/credits-and-commits/get-the-net-balance-of-a-customer) · [Add a manual balance entry](https://docs.metronome.com/api-reference/credits-and-commits/add-a-manual-balance-entry) · [Edit a contract](https://docs.metronome.com/api-reference/contracts/edit-a-contract). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). - A **commit** is the customer's agreement to spend an amount over time. `PREPAID` commits are invoiced up front and drawn down by usage. `POSTPAID` commits are settled after usage, as a true-up. - A **credit** is a free allowance of spend or quantity. It has no invoice. - **Recurring** commits and credits issue a new balance every period. ## Access schedule and invoice schedule | | Access schedule | Invoice schedule | |---|---|---| | Says | When, and how much, balance is available | What the customer is billed | | Credit type | Fiat or a custom credit type | **Must be fiat** | | On | Every commit and credit | Prepaid commits only, optional | A prepaid commit without an invoice schedule is a pure access grant. A custom credit type on the invoice schedule returns `400` "Credit type must be a fiat currency", and only a live call reveals it. ## How it connects Commits and credits live on a contract and reference a product. `applicable_product_ids` or `applicable_product_tags` limit what they pay for; leaving both out means everything. On invoices, a purchase shows as a `commit_purchase` line and a drawdown as a negative `applied_commit_or_credit` line. A parent can share commits with child contracts. ## Gotchas - Lower `priority` numbers draw down first. - `rollover_fraction`, from 0 to 1, is the share carried into a renewal. `0` means the balance is lost on transition. - Pass a `uniqueness_key` on every grant, so a retry can't grant twice. - An invoiced commit can't be archived until its invoices are voided. Rollover commits can't be edited; edit the original on the previous contract. - A manual ledger entry needs the commit's current `segment_id`. - The net balance is the spendable truth. The balance list can differ by anything rolled over to an archived successor. ## How metro handles it | Command | Does | |---|---| | `metro customer balances --ingest-alias=acme-corp --sandbox --json` | Balances, plus `spendableNet`, which compares the net balance with the list | | `metro ledger-adjustment preflight --amount=` | A manual ledger entry on one balance segment | | `metro ledger-adjustment preflight --archive-balance-id=` | Archives a whole grant | | `metro ledger-adjustment preflight --grant=credit` or `--grant=commit` | Adds a new credit, or a complimentary prepaid commit, through a contract edit | | `metro credit preview --shape complimentary-credit-grant --file credit.json --sandbox` | Offline preview of a grant | | `metro credit preview --shape paid-credit-top-up --file topup.json --sandbox` | Offline preview of a payment-gated top-up | metro refuses an addition while the net balance and the balance list disagree for that credit type, and warns with `MTR-CREDIT-NET-001`. When they disagree, trust the net. See [Credits and commits](/docs/guides/credits-and-commits). Metronome docs: [Apply credits and commits](https://docs.metronome.com/pricing-packaging/apply-credits-commits). --- # Subscriptions & seats > Recurring subscription charges, quantity, seat-based subscriptions and proration. Source: https://metrocli.com/docs/concepts/subscriptions-and-seats/ · Docs index: https://metrocli.com/llms.txt A subscription is a recurring line on a contract, priced by a `SUBSCRIPTION` product's rate, which sets its `billing_frequency`. Quantity is the number of subscriptions, usually seats. > **Metronome's reference:** [Edit a contract](https://docs.metronome.com/api-reference/contracts/edit-a-contract) · [Get a contract (v2)](https://docs.metronome.com/api-reference/contracts/get-a-contract-v2) · [Get subscription quantity history](https://docs.metronome.com/api-reference/contracts/get-subscription-quantity-history) · [Get subscription seats history](https://docs.metronome.com/api-reference/contracts/get-subscription-seats-history). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). Each subscription has a collection schedule (`ADVANCE` or `ARREARS`), proration settings, and a quantity mode: | Mode | Set at create | Change later | |---|---|---| | `QUANTITY_ONLY` (default) | `initial_quantity` | `quantity_updates`: an absolute `quantity` or a `quantity_delta` | | `SEAT_BASED` | `seat_config.seat_group_key`, `initial_seat_ids` | `seat_updates`: add or remove seat IDs, or unassigned seats | Seats aren't a separate object. They're a view of a `SEAT_BASED` subscription. A seat ID is whatever you assign, usually your own user ID. You can switch from `QUANTITY_ONLY` to `SEAT_BASED` once, and it can't be undone. ## How it connects The subscription rate's `product_id` points at a `SUBSCRIPTION` product on the contract's rate card. The `subscription_id` comes from the contract, at `data.subscriptions[].id`. All changes go through a contract edit. ## Proration - Increases are prorated. `BILL_IMMEDIATELY` (needs `ADVANCE`) charges right away. `BILL_ON_NEXT_COLLECTION_DATE` adds the amount to the next invoice. - Decreases take effect at the next billing boundary. - Proration is set per subscription, not per seat. ## Gotchas - `quantity_updates` on a `SEAT_BASED` subscription returns `400`. - On a `SEAT_BASED` subscription the contract's quantity schedule shows only the initial state. Use the seats history for current state. - `subscription_id` changes when a plan change creates a new contract. Look it up again; don't cache it. - A subscription bills on its own `billing_frequency`, not the commit's. A subscription-rate override without `billing_frequency` is silently ignored. - Past-dated quantity changes don't restate finalized invoices. - Removing a seat that isn't assigned does nothing, with no error. ## How metro handles it | Command | Does | |---|---| | `metro subscription add preflight --product-id= --billing-frequency=MONTHLY --quantity=10` | Adds a `QUANTITY_ONLY` subscription. Refuses a non-subscription product, a missing rate at that frequency, or a duplicate unless `--allow-duplicate`. | | `metro subscription add preflight --file=subscription.yaml` | Any subscription, including `SEAT_BASED` | | `metro subscription set-quantity preflight --subscription-id= --quantity=12` | Changes quantity. `--delta=` works too; metro always sends the absolute quantity. | | `metro subscription seats preflight --subscription-id= --add-seat-ids=a,b` | Adds or removes seats, assigned or unassigned | | `metro subscription history inspect --customer-id --contract-id --subscription-id --sandbox --plan` | A read plan for a subscription's history | See [Subscriptions and seats](/docs/guides/subscriptions-and-seats). --- # Invoices > Scheduled charges, finalization and voids. Source: https://metrocli.com/docs/concepts/invoices/ · Docs index: https://metrocli.com/llms.txt An invoice is a billing statement on a customer's contract. Metronome builds it from usage, rates and contract terms, finalizes it, and sends it to the billing provider, for example Stripe. > **Metronome's reference:** [How Metronome invoices work](https://docs.metronome.com/guides/implement-metronome/core-concepts/how-invoicing-works) · [Void an invoice](https://docs.metronome.com/api-reference/invoices/void-an-invoice) · [Regenerate an invoice](https://docs.metronome.com/api-reference/invoices/regenerate-an-invoice) · [Update invoice issue date](https://docs.metronome.com/api-reference/contracts/update-invoice-issue-date). These pages are the source of truth for every field; metro's page covers how metro handles it. What metro wraps, endpoint by endpoint: [Metronome API coverage](/docs/reference/api-coverage). ## Types | Type | Created by | |---|---| | `USAGE` | Metronome, each billing period | | `SCHEDULED` | Scheduled charges, or a commit's invoice schedule | | `AD_HOC` | A one-off charge | | `PARENT_INVOICE`, `CHILD_INVOICE` | Hierarchy aggregation | | `HISTORICAL` | Historical invoice creation | Status moves `DRAFT`, then `FINALIZED`, then optionally `VOID`. ## How it connects An invoice belongs to a customer and a contract. Lines reference `product_id`; `applied_commit_or_credit` lines reference `commit_id`. `external_invoice.id` is the billing provider's invoice. Billing provider configs live on the customer, and contracts inherit them. ## When invoices finalize There is no finalize endpoint. Invoices finalize on their own: - `USAGE`: about 24 hours after the period ends. - Future-dated `SCHEDULED`: at the scheduled time. - Past-dated `SCHEDULED`, created through a contract edit: immediately, and pushed to Stripe within seconds. Once an invoice finalizes, Metronome pushes it to the billing provider in the background. `leave_stripe_invoices_in_draft` keeps the Stripe invoice in draft while Metronome's still finalizes. ## Gotchas - Voiding works only on finalized invoices, and never refunds Stripe. Billing-provider reconciliation is separate. - Regenerate works only on void invoices and returns a new invoice ID. - The issue date changes only on `DRAFT` invoices, and the new date must come before the contract's end. - `HISTORICAL` invoices finalize immediately and are never pushed to Stripe. - Stripe collapses invoices with more than 250 lines into one line, rejects decimal quantities, and accepts charges between $0.50 and $999,999.99. - Billing provider config archives are permanent. To change collection method, archive and create a new one. ## How metro handles it | Command | Does | |---|---| | `metro invoice inspect --invoice-id --sandbox --plan` | A read plan: invoice get and its payments | | `metro invoice issue-date preview --file issue-date.json --sandbox` | Offline preview of moving a draft invoice's issue date. Apply is blocked in this release. | | `metro billing-provider cutover preflight --collection-method=send_invoice` | Archives the current Stripe config and sets a new one | See [Invoices](/docs/guides/invoices). Metronome docs: [How invoicing works](https://docs.metronome.com/guides/implement-metronome/core-concepts/how-invoicing-works). --- # Shapes and workspaces > Why metro works in shapes, and sandbox versus production. Source: https://metrocli.com/docs/concepts/shapes-and-workspaces/ · Docs index: https://metrocli.com/llms.txt metro has two ways to describe a change: **shapes**, which are checked offline, and **ops**, which read your tenant and write a plan. **Workspace packs** decide which billing intents metro knows about. And every live call names a **tenant**. ## Shapes A shape is a reviewed, local contract for one kind of change, in JSON or YAML. metro validates it before any Metronome client loads, so a malformed payload never reaches the API. ```bash metro shape list metro shape explain free-credit-trial metro validate --shape free-credit-trial --file trial.json --json metro package preview --shape free-credit-trial --file trial.json --sandbox --json ``` A shape encodes the traps for you. `free-credit-trial`, for example, enforces `commit_duration.unit: PERIODS`, a string `duration.value`, `starting_at_offset` and proration, "so agents never hand-craft this payload". Each shape has a maturity and blocked modes. Today every shape is `local-validated`: explain, validate and preview work; apply through the shape is blocked. Live writes go through ops instead. The full list is on [Shapes](/docs/reference/shapes); the rules they check are on [Validators](/docs/reference/validators). ## Ops An op is a live command with a `preflight` and an `apply`: `metro customer create`, `metro contract move-plan`, `metro ledger-adjustment` and the rest. Preflight reads the tenant, so it can check things a shape can't: that an alias is free, that a balance exists, that a contract doesn't overlap. See the [safety contract](/docs/agents/safety-contract). | | Shape preview | Op preflight | |---|---|---| | Talks to Metronome | No | Reads only | | Output | A payload plan and a `sha256:` hash | A plan file with exact requests and a `payloadHash` | | Can apply | Not in this release | Yes, with `--confirm-hash` and a typed token | ## Workspace packs metro is split in two. `metro-core` knows the Metronome API, the shapes and the evidence gates. A **workspace pack** adds billing intents on top, like "move a customer to another package". The public build ships the `generic` pack. ```bash metro workspace list metro workspace current metro plan list ``` `metro plan list` shows the pack's intents, and `metro plan --sandbox --json` maps one to its best shape, the paths it rejects, and the commands to run. The generic pack binds to your own catalog through `metro catalog bind`; it has no hardcoded IDs. The active pack resolves in this order: `metro workspace use`, then `METRO_WORKSPACE_PACK`, then the session, then the profile, then `~/.metro/config.json`, then the built-in default. ## Sandbox and production Sandbox and production are two Metronome tenants behind one base URL, `https://api.metronome.com`. The key picks the tenant. | | Sandbox | Production | |---|---|---| | Key | `METRONOME_SANDBOX_KEY` | `METRONOME_PROD_KEY` | | Flag | `--sandbox` | `--prod` | | Typed token for a write | `--confirm-live-apply=I_UNDERSTAND_THIS_WILL_WRITE_LIVE_METRONOME_SANDBOX` | `--confirm-prod-apply=I_UNDERSTAND_BILLING_SIDE_EFFECTS` | | When | Always first | After the sandbox readback passes, with a typed yes for that change | metro refuses a sandbox key equal to the production key, in either direction. A plan's hash covers its tenant, so a sandbox plan can't be applied to production. ## Tenant snapshots `metro catalog bind --sandbox --write` saves your IDs to `~/.metro/profiles.json`, and a versioned model to `~/.metro/snapshots/sandbox.json`. `metro tenant snapshot diff --sandbox --markdown` shows what changed since the last bind, and `--against=production` compares the two tenants. --- # Commands > Every metro command and its output contract. Source: https://metrocli.com/docs/reference/commands/ · Docs index: https://metrocli.com/llms.txt Every metro command, its mode, whether it touches the API, and its output `schemaVersion`. Prefer `--json` when scripting; agents load `--markdown`. > **Source.** Generated from `metro docs command-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.command-reference.v1`. - schemaVersion: `metro.docs.command-reference.v1` ## Commands | id | command | group | mode | status | apiAccess | schemaVersion | description | | --- | --- | --- | --- | --- | --- | --- | --- | | init | metro init [--agent] [--prod] [--plain] | init | setup | local | read | none | First run: create ~/.metro/.env (mode 600), add the sandbox key (hidden input), check it with one read-only Metronome call, and leave metro read-only. --agent prints the steps for a human instead of prompting; --prod adds only the production key after a y/N confirmation. | | init.check | metro init --check [--json] | init | inspect | local | read | metro.init.check.v1 | Report each configured key as missing, rejected, or working. Exits 1 while the sandbox key is not working. | | shape.list | metro shape list [--json] | shape | explain | local | none | metro.shape.list.v1 | List supported reviewed shapes and maturity levels. | | shape.explain | metro shape explain [--json] | shape | explain | local | none | metro.shape.explain.v1 | Explain a shape, including required input, maturity, blocked modes, rule IDs, and sources. | | validate.shape | metro validate --shape --file [--json] | validate | validate | local | none | metro.validation.v1 | Validate local JSON or YAML input against a supported shape before any API client loads. | | input.normalize | metro input normalize (--shape \|--api ) --file [--json] | input | validate | local | none | metro.input.normalize.v1 | Normalize local JSON or YAML workflow shape input or expert API request input into stable canonical JSON with validation status, secret-scan refusal, and deterministic hash output. | | workspace.explain | metro workspace explain [--sandbox\|--prod] [--json] | workspace | explain | local | none | metro.workspace.v1 | Explain the active workspace catalog model, rate-card bindings, API token conventions, and plan intents for optimal shape routing. | | workspace.status | metro workspace status --file --profile [--check-env] [--json] | workspace | explain | local | none | metro.workspace.status.v1 | Bind a tenant profile to the workspace model and report whether the Metronome key env var is configured (name only, never the secret). | | workspace.list | metro workspace list [--json] | workspace | explain | local | none | metro.workspace.list.v1 | List installed workspace packs and show which pack is active from sticky resolution. | | workspace.current | metro workspace current [--json] | workspace | explain | local | none | metro.workspace.current.v1 | Show the resolved workspace pack and which source won (cli flag, env, session, profile, sticky config, or built-in default). | | workspace.use | metro workspace use [--write] [--json] | workspace | explain | local | none | metro.workspace.use.v1 | Set the active workspace pack for this process; with --write, persist defaultWorkspacePack in ~/.metro/config.json so later shells stay sticky. | | plan.template | metro plan template (--sandbox\|--prod) [--out ] [--token ] [--action-code ] [--display-name ] [--price ] [--file ] [--profile ] [--json] | plan | explain | local | none | metro.workspace.input-template.v1 | Emit a focused inputTemplate JSON payload for a workspace intent, optionally writing it to a file for validate/preview follow-on. | | plan.list | metro plan list [--json] | plan | explain | local | none | metro.workspace.plan.list.v1 | List workspace-aware plan intents that map billing goals to optimal shapes and rejected API paths. | | plan.intent | metro plan (--sandbox\|--prod) [--token ] [--action-code ] [--display-name ] [--price ] [--file ] [--profile ] [--json] | plan | preview | local | none | metro.workspace.plan.v1 | Build a workspace-aware plan for a billing intent: optimal shape, catalog mode, rejected paths, commands, verification reads, and input templates. | | route.goal | metro route --goal "" [--api ] (--sandbox\|--prod) [--json] | route | validate | local | none | metro.workspace.route.v1 | Match a billing goal or API endpoint to the optimal workspace plan intent and refuse suboptimal catalog paths. | | audit.export.classify | metro audit export classify --file [--token ] (--sandbox\|--prod) [--json] | audit | validate | local | none | metro.workspace.audit-export.v1 | Classify exported Metronome audit log rows by action histogram and map to workspace plan intents (local file only). | | audit.export.plan | metro audit export plan --token (--sandbox\|--prod) [--json] | audit | explain | local | none | metro.workspace.audit-export.v1 | Build the local audit export workflow (security.getAuditLogs read plan steps + classify); does not perform live reads. | | package.preview.pro-annual-self-serve-v2 | metro package preview --shape pro-annual-self-serve-v2 --file (--sandbox\|--prod) [--json] | package | preview | local | none | metro.preview.v1 | Preview annual self-serve package v2 with separable plan fee and monthly-drip or lump-sum recurring_commits. | | package.preview.free-credit-trial | metro package preview --shape free-credit-trial --file (--sandbox\|--prod) [--json] | package | preview | local | none | metro.preview.v1 | Validate and preview a free-trial package with recurring credit grants, auto-expiry (duration in days), and no Stripe. Enforces commit_duration.unit PERIODS, duration.value as a string, starting_at_offset, and proration - do not hand-craft this payload. | | package.preview.pro-annual | metro package preview --shape pro-annual --file (--sandbox\|--prod) [--json] | package | preview | local | none | metro.preview.v1 | Build a local package preview payload plan, side-effect summary, verification plan, and canonical hash. | | package.archive.preview.alias-handoff | metro package archive preview --file (--sandbox\|--prod) [--shape package-alias-archive-handoff] [--json] | package | preview | local | none | metro.preview.v1 | Build a local package archive plan that refuses old-version archive until the replacement alias is live and verified, without calling Metronome. | | credit.preview.complimentary-credit-grant | metro credit preview --shape complimentary-credit-grant --file (--sandbox\|--prod) [--json] | credit | preview | local | none | metro.preview.v1 | Build a local complimentary-credit preview payload plan, side-effect summary, verification plan, and canonical hash. | | credit.preview.paid-credit-top-up | metro credit preview --shape paid-credit-top-up --file (--sandbox\|--prod) [--json] | credit | preview | local | none | metro.preview.v1 | Build a local paid credit top-up preview payload plan with fiat invoice schedule, Stripe payment gate, side-effect summary, and read-back plan. | | billing-provider.preview.stripe-attachment | metro billing-provider preview --shape stripe-billing-provider-attachment --file (--sandbox\|--prod) [--json] | billing-provider | preview | local | none | metro.preview.v1 | Build a local Stripe billing-provider attachment payload plan, Stripe draft-behavior plan, verification plan, and canonical hash. | | customer.setup.preview | metro customer setup preview --file (--sandbox\|--prod) [--shape customer-setup] [--json] | customer | preview | local | none | metro.preview.v1 | Build a local customer setup plan with identity, ingest alias collision checks, optional Stripe billing-provider config, hierarchy posture, custom-field approval evidence, read-back checks, and a canonical hash. | | contract.move-plan.preview.no-immediate-invoice | metro contract move-plan preview --file (--sandbox\|--prod) [--shape package-plan-move-no-immediate-invoice] [--json] | contract | preview | local | none | metro.preview.v1 | Build a local package plan-move preview using updateEndDate plus a RENEWAL successor contract, without calling Metronome. | | contract.move-plan.preflight | metro contract move-plan preflight --to= (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--from=] (--sandbox\|--prod) [--cutover=ISO\|--cutover-mode=renewal-boundary\|current-hour\|next-hour] [--out=move.json] [--json] | contract | preflight | live | read | metro.contract-move-plan.preflight.v1 | Live-read customer contracts, invoices, and package aliases; infer renewal-boundary cutover; write move.json plus preview hash for apply. | | customer.resolve | metro customer resolve (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) (--sandbox\|--prod) [--json] | customer | read | live | read | metro.customer.resolve.v1 | Resolve a Metronome customer by UUID, external/custom id, ingest alias, or company name (live list/search). | | customer.balances | metro customer balances (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) (--sandbox\|--prod) [--contract-id=] [--min-balance=] [--only-active] [--only-nonzero] [--out=] [--json] | customer | read | live | read | metro.customer-balances.v1 | Live-read every commit/credit balance for a customer (contracts/list + customerBalances/list), tagging each row with contract_active and ledger_adjustable. | | tenant.snapshot | metro tenant snapshot show\|refresh\|diff [--sandbox\|--prod] [--against=prev\|production\|] [--json\|--markdown] [--dir ] | tenant | explain | local | none | metro.tenant.snapshot.show.v1 | Show, re-classify, or diff the local tenant snapshot under ~/.metro/snapshots (pattern + bound catalog). Live refresh of inventory is metro catalog bind --write. | | catalog.bind | metro catalog bind (--sandbox\|--prod) [--write] [--file ] [--profile ] [--json] | catalog | read | live | read | metro.catalog.bind.v1 | Discover rate cards, products, billable metrics, and credit types; write workspaceCatalog into profiles.json for generic pack plans. | | contract.move-plan.apply | metro contract move-plan apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | contract | apply | pack-op | write | metro.contract-move-plan.apply.v1 | Dry-run validates move.json offline; live --apply runs updateEndDate + RENEWAL successor with post-apply read-back. Production requires ALLOW_DANGEROUS_SCRIPT or --confirm-prod-apply. | | contract.move-plan.bulk-preflight | metro contract move-plan bulk-preflight --to= --roster-file= (--sandbox\|--prod) [--cutover=ISO\|--cutover-mode=…] [--out-dir=] [--out=manifest.json] [--delay-ms=300] [--json] | contract | preflight | live | read | metro.contract-move-plan.bulk-preflight.v1 | Runs contract move-plan preflight per customer in a roster file (one customer id per line), flags predecessor balance carrying into RENEWAL successors, and writes a bulk manifest with per-customer confirm hashes. | | contract.move-plan.bulk-apply | metro contract move-plan bulk-apply --file (--sandbox\|--prod) [--apply] [--limit=N] [--delay-ms=300] [--confirm-prod-apply=] [--json] | contract | apply | pack-op | write | metro.contract-move-plan.bulk-apply.v1 | Replays contract move-plan apply for every preflight-ok entry in a bulk manifest, continuing on per-customer failure. Use --limit=N to canary before the full roster; each entry still requires its own preflight confirm hash. | | contract.extend-trial.preflight | metro contract extend-trial preflight --extend-to=\|--extend-by-days= (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--contract-id=] (--sandbox\|--prod) [--out=extend.json] [--json] | contract | preflight | live | read | metro.contract-extend-trial.preflight.v1 | Live-read the active contract, compute an hour-boundary extension of its current ending_before, and write an updateEndDate payload plus confirm hash for apply. Refuses truncations and open-ended contracts. | | contract.extend-trial.apply | metro contract extend-trial apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | contract | apply | pack-op | write | metro.contract-extend-trial.apply.v1 | Dry-run validates the extend.json payload offline; live --apply runs a single updateEndDate call with post-apply read-back. Production requires ALLOW_DANGEROUS_SCRIPT or --confirm-prod-apply. | | contract.expire.preflight | metro contract expire preflight (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--contract-id=] [--cutover-mode=current-hour\|next-hour\|--ending-before=] (--sandbox\|--prod) [--out=expire.json] [--json] | contract | preflight | live | read | metro.contract-expire.preflight.v1 | Live-read the active contract and write an updateEndDate truncation payload (default cutover: current UTC hour). Prefer --customer-id for a 1-call resolve. | | contract.expire.apply | metro contract expire apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | contract | apply | pack-op | write | metro.contract-expire.apply.v1 | Dry-run validates expire.json offline; live --apply runs updateEndDate with post-apply read-back proving ending_before. | | ledger-adjustment.preflight | metro ledger-adjustment preflight (--amount=\|--archive-balance-id=) --reason="" (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--contract-id=] [--balance-id=] (--sandbox\|--prod) [--out=ledger.json] [--json] | ledger-adjustment | preflight | live | read | metro.ledger-adjustment.preflight.v1 | Live-read customer balances, resolve exactly one target commit balance (by contract/balance filter or unambiguous match), and write a confirm-hashed payload for apply. --amount does a partial addManualBalanceLedgerEntry adjustment. --archive-balance-id fully archives one grant via contracts.edit archive_credits/archive_commits (all-or-nothing, no amount) - the two are mutually exclusive. Refuses ambiguous targets and removals larger than the available balance. | | ledger-adjustment.apply | metro ledger-adjustment apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | ledger-adjustment | apply | pack-op | write | metro.ledger-adjustment.apply.v1 | Dry-run validates the ledger.json payload offline; live --apply detects the payload shape and runs either addManualBalanceLedgerEntry (partial amount) or contracts.edit archive_credits/archive_commits (full grant archive), with post-apply balance read-back. Production requires ALLOW_DANGEROUS_SCRIPT or --confirm-prod-apply. Highest-risk write - requires owner-approved business reason. | | contract.repair-accidental.preflight | metro contract repair-accidental preflight --archive-contract-id= --keep-contract-id= --reason="" (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--restore-ending-before=] (--sandbox\|--prod) [--out=repair.json] [--json] | contract | preflight | live | read | metro.contract-repair-accidental.preflight.v1 | Live-read both named contracts plus recent customer invoices, refuse if the contract to archive has any FINALIZED or Stripe-synced invoice (danger-zone SKILL.md §1.1/§7 - void_invoices never refunds Stripe), and write a contracts.archive(void_invoices:true) [+ optional updateEndDate restore] payload with a confirm hash. Which contract is "accidental" is always an explicit human-supplied id, never inferred. | | contract.repair-accidental.apply | metro contract repair-accidental apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | contract | apply | pack-op | write | metro.contract-repair-accidental.apply.v1 | Dry-run validates the repair.json payload offline; live --apply archives the accidental contract with void_invoices:true, optionally restores the kept contract's ending_before, then reads both back. Production requires ALLOW_DANGEROUS_SCRIPT or --confirm-prod-apply. | | billing-provider.cutover.preflight | metro billing-provider cutover preflight --collection-method=send_invoice\|charge_automatically --reason="" (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--old-config-id=] [--stripe-customer-id=] [--delivery-method-id=] [--leave-stripe-invoices-in-draft] (--sandbox\|--prod) [--out=cutover.json] [--json] | billing-provider | preflight | live | read | metro.billing-provider-cutover.preflight.v1 | Live-read the customer's active Stripe billing-provider configuration, refuse if none/ambiguous or already on the requested method, reuse the existing stripe_customer_id/delivery_method_id unless overridden, and write an archiveCustomerBillingProviderConfigurations + setCustomerBillingProviderConfigurations [+ optional updateConfig leave_stripe_invoices_in_draft] payload with a confirm hash. Does not touch any contract - pair with contract move-plan/repair-accidental for the contract side. | | billing-provider.cutover.apply | metro billing-provider cutover apply --file (--sandbox\|--prod) --confirm-hash [--apply --confirm-live-apply=\|--confirm-prod-apply=] | billing-provider | apply | pack-op | write | metro.billing-provider-cutover.apply.v1 | Dry-run validates the cutover.json payload offline; live --apply optionally sets leave_stripe_invoices_in_draft, archives the old billing-provider configuration, sets the new one, then reads both back. Production requires ALLOW_DANGEROUS_SCRIPT or --confirm-prod-apply. | | package.customers | metro package customers --package-id=\|--alias= (--sandbox\|--prod) [--json] | package | read | live | read | metro.package-customers.v1 | Live-read which customers currently have an active contract on a package, given either a raw package id or its alias. Resolves each active contract to a customer (name, external id, ingest aliases). Does not cross into Stripe for email. | | package.list | metro package list [--package-id=\|--alias=\|--search=] [--only-archived\|--only-active] [--out=] (--sandbox\|--prod) [--json] | package | read | live | read | metro.package-list.v1 | Live-read inventory of every package version in the tenant, including archived ones, always following packages/list next_page to completion so the 100-row page size never truncates the result. Supports filtering by raw id, alias, or free-text search, and an optional --out dump to a local JSON file. | | product.retire.preview.product-rate-retirement | metro product retire preview --file (--sandbox\|--prod) [--shape product-rate-retirement] [--json] | product | preview | local | none | metro.preview.v1 | Build a local product/rate retirement plan that closes affected rate-card entries before optional product archive, without calling Metronome. | | rate-card.dimensional.preview | metro rate-card dimensional preview --file (--sandbox\|--prod) [--shape dimensional-rate-card] [--json] | rate-card | preview | local | none | metro.preview.v1 | Build a local dimensional rate-card plan for one action-code USAGE product plus per-action addRates entries, without calling Metronome. | | invoice.issue-date.preview | metro invoice issue-date preview --file (--sandbox\|--prod) [--shape invoice-issue-date-update] [--json] | invoice | preview | local | none | metro.preview.v1 | Build a local DRAFT invoice issue-date update plan with explicit Stripe behavior, contract-end evidence, and read-back checks, without calling Metronome. | | subscription.contract.preview.direct | metro subscription contract preview --file (--sandbox\|--prod) [--shape direct-subscription-contract] [--json] | subscription | preview | local | none | metro.preview.v1 | Build a local direct subscription contract plan with rate-card identity, frequency, quantity/seat source, billing-provider, and read-back checks, without calling Metronome. | | custom-contract.preview.enterprise | metro custom-contract preview --file (--sandbox\|--prod) [--shape enterprise-custom-contract] [--json] | custom-contract | preview | local | none | metro.preview.v1 | Build a local direct enterprise custom-contract plan with explicit customer identity, Stripe billing-provider config, recurring commit, optional bonus commits, optional seat updates, side-effect summary, read-back plan, and canonical hash. | | usage.ingest.preview | metro usage ingest preview --file (--sandbox\|--prod) [--shape usage-ingest-preview] [--json] | usage | preview | local | none | metro.preview.v1 | Build a local usage ingest preview plan with event-shape validation, transaction-id idempotency, invoice-period risk review, canary gating, and read-back checks, without calling Metronome. | | api.catalog | metro api catalog [--family ] [--json] | api | explain | local | none | metro.api.catalog.v1 | List reviewed Metronome endpoint IDs, methods, paths, support status, source IDs, and local-only live-execution state. | | api.explain | metro api explain [--json] | api | explain | local | none | metro.api.endpoint.v1 | Explain one reviewed endpoint contract, including operation type, permission scope, request/response contract, gates, current workflow commands, and sources. | | api.search | metro api search [--query ] [--family ] [--json] | api | explain | local | none | metro.api.search.v1 | Search reviewed endpoint IDs, titles, methods, paths, summaries, source IDs, policy gates, and command text without loading API clients. | | api.diff | metro api diff [--json] | api | explain | local | none | metro.api.diff.v1 | Compare two reviewed endpoint contracts by endpoint ID, including local method/path metadata, request and response contracts, policy gates, command coverage, source IDs, and disabled live-execution state. | | api.export | metro api export [--family ] [--json] | api | export | local | none | metro.api.export.v1 | Export a source-linked local documentation bundle for reviewed API endpoint docs, command docs, workflow shape docs, validator rules, gotchas, approval policies, and checked-in example fixtures without loading API clients. | | api.scopes | metro api scopes [--family ] [--json] | api | explain | local | none | metro.api.permission-scopes.v1 | List expert API permission scopes derived from the reviewed endpoint catalog, including access class, endpoint coverage, approval model, live-execution status, and required gates. | | api.approvals | metro api approvals [--family ] [--json] | api | explain | local | none | metro.api.approval-policies.v1 | List local expert API approval policies by permission scope, including accountable owner role, required approver roles, approval record fields, evidence requirements, confirmation requirement, and disabled live-execution status. | | api.readiness | metro api readiness [--family ] [--summary] [--json] | api | explain | local | none | metro.api.readiness.v1 | Summarize reviewed read and write endpoint readiness, including compact gap counts with --summary, endpoint-specific validator coverage, local read-plan coverage, write proof-ladder coverage, and disabled live-read/write status. | | api.validate | metro api validate --file [--json] | api | validate | local | none | metro.api.validation.v1 | Validate a local expert API request file against a reviewed endpoint id, source-linked contract, permission scope, and endpoint-specific safety rules without loading API clients. | | api.read-plan | metro api read-plan --file (--sandbox\|--prod) [--json] | api | inspect-plan | local | none | metro.api.read-plan.v1 | Build a local expert API read plan for a reviewed read endpoint, including explicit tenant, endpoint-specific request validation, request hash, future confirm-live-read gate, and stable output contract without loading API clients. | | api.read-preflight | metro api read-preflight --file (--sandbox\|--prod) [--read-gate ] [--confirm-live-read ] [--json] | api | explain | local | none | metro.api.read-preflight.v1 | Build a local expert API read preflight summary that combines endpoint selection, explicit tenant, request validation, local read-plan evidence, optional read-gate validation, live-read authorization evidence, and remaining runtime blockers without loading API clients. | | api.read-gate.template | metro api read-gate template --read-plan [--profile-resolution ] [--profile ] [--key-env ] [--key-fingerprint ] [--authorization-id ] [--approved-by ] [--audit-log ] [--json] | api | explain | local | none | metro.api.read-gate.v1 | Build a local expert API read-gate manifest that binds a reviewed read-plan file hash to tenant profile-resolution evidence, current-turn authorization, audit-safe request summary rules, and stable output verification without enabling live reads. | | api.read-gate.validate | metro api read-gate validate --file [--json] | api | validate | local | none | metro.api.read-gate.validation.v1 | Validate local expert API read-gate evidence for read-plan hash binding, tenant profile, current-turn authorization, audit-safe summaries, read-only runner requirements, and output verification while live reads remain disabled. | | api.read-result.verify | metro api read-result verify --file [--json] | api | verify | local | none | metro.api.read-result.validation.v1 | Validate mocked expert API read output for read-gate binding, request hash, mocked transport, response hash, read-only request summary, and response-contract checks without enabling live reads. | | api.read-mock | metro api read-mock --file --read-gate --mock-response [--actor ] [--json] | api | verify | local | none | metro.api.read-mock.v1 | Run the local mocked expert API read pipeline for a reviewed endpoint, binding request input to a read gate, mocked response data to read-result verification, and a read-audit template without live API access. | | api.read-pipeline | metro api read-pipeline --file --read-gate --mock-response --out --actor (--dry-run\|--write) [--timestamp ] [--json] | api | audit | local | none | metro.api.read-pipeline.v1 | Run the local mocked expert API read pipeline and prepare or append the read-audit JSONL row in one step, using reviewed endpoint IDs, read-gate evidence, mocked response data, explicit actor, and explicit local audit output while live reads remain disabled. | | api.read-audit.template | metro api read-audit template --read-gate --read-result [--actor ] [--json] | api | explain | local | none | metro.api.read-audit.template.v1 | Build a local JSONL read-audit row template from validated read-gate and mocked read-result evidence, with request hashes, response hashes, key fingerprints, and audit-safe summaries only. | | api.read-audit.write | metro api read-audit write --read-gate --read-result --out --actor (--dry-run\|--write) [--timestamp ] [--json] | api | audit | local | none | metro.api.read-audit.write.v1 | Build and optionally append one local expert API read-audit JSONL row from validated read-gate and mocked read-result evidence, requiring an explicit output path, actor, and dry-run or write mode while live reads remain disabled. | | api.read-audit.validate | metro api read-audit validate --file [--json] | api | validate | local | none | metro.api.read-audit.validation.v1 | Validate local expert API read-audit JSONL for read-gate binding, key fingerprints, read-only request summaries, response hashes, verification status, and secret-free evidence. | | api.read | metro api read --file (--sandbox\|--prod) --read-gate --confirm-live-read [--json] | api | read | live-guarded | read | metro.api.read-result.v1 | Execute a guarded live Metronome read for reviewed endpoints when read-gate evidence, current-turn authorization, and tenant key configuration are satisfied. Supported: contracts.get.v2, customers.get, invoices.listForCustomer. | | api.apply | metro api apply --file --sandbox --apply-gate --approval-record --confirm-live-apply [--json] | api | apply | live-guarded | write | metro.api.apply-live-result.v1 | Execute a guarded live sandbox Metronome write when apply-gate and approval-record evidence match. Currently limited to contracts.create in sandbox only. | | api.preview | metro api preview --file (--sandbox\|--prod) [--json] | api | preview | local | none | metro.api.preview.v1 | Build a local expert API preview contract with explicit tenant, endpoint-specific validation, source-linked request summary, policy gates, and a stable preview hash without loading API clients. | | api.preflight.template | metro api preflight template --preview [--profile-resolution ] [--approval-id ] [--json] | api | explain | local | none | metro.api.preflight.v1 | Build a local expert API preflight template that binds a metro.api.preview.v1 output to tenant profile-resolution evidence, approval, audit, idempotency, sandbox proof, canary, read-back, and rollback evidence before any future expert apply. | | api.preflight.validate | metro api preflight validate --file [--json] | api | validate | local | none | metro.api.preflight.validation.v1 | Validate local expert API preflight evidence for preview-hash binding, endpoint source proof, permission scope, tenant profile-resolution evidence, approval, idempotency, audit, sandbox proof, canary, read-back, and rollback before any future expert apply. | | api.sandbox-proof.template | metro api sandbox-proof template --preview --preflight [--reviewed-by ] [--owner ] [--json] | api | explain | local | none | metro.api.sandbox-proof.v1 | Build a local expert API sandbox-proof template that binds a sandbox API preview and preflight to canary, read-back, invoice/Stripe behavior, and rollback/remediation evidence without enabling expert API apply. | | api.sandbox-proof.validate | metro api sandbox-proof validate --file [--json] | api | validate | local | none | metro.api.sandbox-proof.validation.v1 | Validate local expert API sandbox-proof evidence for reviewed sandbox tenant, preview/preflight hash binding, canary result, read-back, invoice/Stripe behavior, rollback, and disabled expert API apply state. | | api.apply-gate.template | metro api apply-gate template --preview --preflight [--sandbox-proof ] [--profile-resolution ] [--approval-id ] [--owner ] [--key-env ] [--key-fingerprint ] [--audit-log ] [--json] | api | explain | local | none | metro.api.apply-gate.v1 | Build a local expert API apply-gate manifest that file-hashes reviewed API preview, API preflight, sandbox proof, tenant profile-resolution, approval, key fingerprint, audit, verification, rollback, and idempotency evidence without enabling expert API apply. Production gates bind sandbox proof by reviewed endpoint id and request hash while binding approval to the production preview hash. | | api.apply-gate.validate | metro api apply-gate validate --file [--json] | api | validate | local | none | metro.api.apply-gate.validation.v1 | Validate a local expert API apply-gate manifest and referenced preview, preflight, sandbox-proof, and tenant profile-resolution files before any future expert API apply runner can use the evidence, including production-to-sandbox proof binding by request hash. | | api.approval-record.template | metro api approval-record template --apply-gate [--approval-id ] [--requested-by ] [--approved-by ] [--owner ] [--business-purpose ] [--expires-at ] [--json] | api | explain | local | none | metro.api.approval-record.v1 | Build a durable local expert API approval record from a validated API apply-gate file hash, preserving reviewed preview, sandbox-proof, tenant profile, audit, read-back, rollback, idempotency, and owner approval evidence without serving as current-turn authorization or enabling expert API apply. | | api.approval-record.validate | metro api approval-record validate --file [--json] | api | validate | local | none | metro.api.approval-record.validation.v1 | Validate a durable local expert API approval record against the referenced apply-gate file hash, endpoint policy, approval metadata, tenant profile, sandbox proof, rollback, idempotency, and disabled-live-apply state before it can be used as future evidence. | | api.apply-audit.template | metro api apply-audit template --approval-record [--actor ] [--json] | api | explain | local | none | metro.api.apply-audit.template.v1 | Build a local planned expert API apply-audit row from a validated approval-record file, carrying approval, apply-gate, tenant profile, idempotency, rollback, and read-back evidence without claiming current-turn authorization or enabling expert API apply. | | api.apply-audit.write | metro api apply-audit write --approval-record --out --actor (--dry-run\|--write) [--timestamp ] [--json] | api | audit | local | none | metro.api.apply-audit.write.v1 | Prepare or append one local planned expert API apply-audit JSONL row after approval-record validation, using explicit dry-run/write mode and append-only local output while live expert API apply remains disabled. | | api.apply-audit.validate | metro api apply-audit validate --file [--json] | api | validate | local | none | metro.api.apply-audit.validation.v1 | Validate local planned expert API apply-audit JSONL rows for approved approval-record binding, apply-gate hashes, tenant profile, read-back plan, rollback, idempotency, and disabled-live-apply state. | | api.apply-readback.verify | metro api apply-readback verify --apply-audit --read-result [--row ] [--json] | api | verify | local | none | metro.api.apply-readback.verify.v1 | Compare local planned expert API apply-audit read-back checks with verified mocked read-result evidence, binding read-back proof without claiming live apply execution, live read execution, or current-turn authorization. | | api.apply-result.template | metro api apply-result template --apply-audit --apply-readback [--row ] [--json] | api | template | local | none | metro.api.apply-result.template.v1 | Build a local expert API apply-result contract template from planned apply-audit and compatible apply-readback evidence without enabling live apply. | | api.apply-result.validate | metro api apply-result validate --file --apply-audit --apply-readback [--row ] [--json] | api | verify | local | none | metro.api.apply-result.validation.v1 | Validate a local expert API apply-result evidence file for endpoint binding, guarded execution metadata, response object IDs, semantic read-back success, rollback, idempotency, and secret-free evidence. | | docs.command-reference | metro docs command-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.command-reference.v1 | Print the command and output contract catalog as machine-readable JSON, Markdown, or generated HTML. | | docs.schema | metro schema [--json] | docs | explain | local | none | metro.docs.command-reference.v1 | Print the same machine-readable command, output, status, and exit-code catalog from a top-level automation-friendly command. | | docs.explain | metro docs explain [--topic ] [--list] [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.explain.v1 | Explain one source-linked documentation topic, list available docs-explain topic families, or render the topic index as generated HTML from local references, including reviewed endpoint IDs, workflow shapes, validator rules, gotchas, permission scopes, command IDs, checked-in example fixtures, and curated operating topics without loading API clients. | | docs.api-reference | metro docs api-reference [--family ] [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.api-reference.v1 | Print the generated reviewed endpoint catalog reference with endpoint IDs, request/response contracts, permission scopes, gates, sources, and local-only execution state. | | docs.evidence-gate-reference | metro docs evidence-gate-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.evidence-gate-reference.v1 | Print the generated evidence-gate reference for preview-only write shapes, including preflight, audit, sandbox-proof, apply-gate coverage, blocked apply commands, source modules, and local-only execution state. | | docs.input-reference | metro docs input-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.input-reference.v1 | Print the generated structured input reference with JSON/YAML adapter scope, metro.input.normalize.v1 output fields, round-trip guarantees, secret-scan behavior, and source-linked proof commands. | | docs.shape-reference | metro docs shape-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.shape-reference.v1 | Print the generated shape catalog reference with required input, maturity, blocked modes, validator rules, and sources. | | docs.validator-reference | metro docs validator-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.validator-reference.v1 | Print the generated validator rule reference with severity, remediation, and shape mappings. | | docs.gotcha-reference | metro docs gotcha-reference [--json\|--html\|--markdown] | docs | explain | local | none | metro.docs.gotcha-reference.v1 | Print the generated gotcha-to-validator coverage reference with current rules, planned rules, gaps, and sources. | | setup.quickstart | metro setup quickstart [--json\|--shell] | setup | explain | local | none | metro.setup.quickstart.v1 | Print the first safe preview path for a new teammate: temp sample files, command schema discovery, profile template, profile resolution, local validation, sandbox preview, expected output cues, a copy/paste shell block, and safety boundaries without live API access. | | harness.list | metro harness list [--json] | harness | explain | local | none | metro.harness.list.v1 | List local harness suites for onboarding, fixture proof, workspace intent plans, and live allowlist audits. | | harness.run | metro harness run --suite [--execute] [--fixture-root ] [--json] | harness | validate | local | none | metro.harness.v1 | Build or execute a local harness suite that proves CLI onboarding, fixtures, workspace plans, or allowlist catalog coverage without live Metronome access. | | harness.intent | metro harness intent (--sandbox\|--prod) [--out ] [--execute] [--json] | harness | preview | local | none | metro.harness.v1 | Plan → template → validate/preview ladder for one workspace billing intent. | | harness.read | metro harness read --file (--sandbox\|--prod) [--execute] [--json] | harness | validate | local | none | metro.harness.v1 | Local read proof ladder: validate → read-plan for a reviewed read endpoint without calling Metronome. | | harness.apply | metro harness apply --file [--execute] [--json] | harness | validate | local | none | metro.harness.v1 | Local sandbox write proof ladder: validate → preview for a reviewed write endpoint without live apply. | | mode.show | metro mode [show] [--json] | setup | explain | local | none | metro.operator-mode.v1 | Show the sticky operator mode ceiling (local-only \| read-only \| read-write) stored in ~/.metro/mode.json. Does not authorize any live call by itself. | | mode.set | metro mode set [--json] | setup | validate | local | none | metro.operator-mode.v1 | Persist the operator mode ceiling until changed. read-only allows live lookups; read-write allows allowlisted writes (confirmation tokens still required). | | mode.reset | metro mode reset [--json] | setup | validate | local | none | metro.operator-mode.v1 | Remove ~/.metro/mode.json and restore the default ceiling (read-only). Raise it with metro mode set read-write only for an approved write. | | install.doctor | metro doctor [--json] | setup | validate | local | none | metro.install.doctor.v1 | Check global metro install health: PATH, npm link target, broken git+ symlinks, ~/.metro/src checkout, and optional gh auth. Prints the canonical install one-liner when something is wrong. | | status.dashboard | metro status [--file ] [--profile ] [--check-env] [--json] | setup | explain | local | none | metro.status.v1 | Print a local dashboard combining operator mode, workspace model summary, optional profile auth check, live endpoint allowlist, and compact API readiness. | | setup.init | metro setup init [--dir ] [--write] [--force] [--json] | setup | validate | local | none | metro.setup.init.v1 | Plan or write ~/.metro/profiles.json from the local profile template without loading API clients or printing secrets. | | setup.template | metro setup template [--json] | setup | explain | local | none | metro.profiles.v1 | Print a local profile template with tenant-scoped Metronome key environment variable names. | | setup.doctor | metro setup doctor --file [--json] | setup | validate | local | none | metro.setup.doctor.v1 | Validate a local profile file and report environment variable presence by name only without loading API clients. | | setup.auth | metro setup auth --file [--profile ] [--check-env] [--json] | setup | validate | local | none | metro.setup.auth.v1 | Check profile key env var presence and list the current live read/sandbox-apply endpoint allowlist without printing secret values. | | setup.resolve | metro setup resolve --file --profile --key-fingerprint [--expect-tenant ] [--check-env] [--json] | setup | validate | local | none | metro.profile.resolve.v1 | Resolve one named tenant profile into secret-free local binding evidence for future read gates or preflight manifests without authorizing live API access. | | release.readiness | metro release readiness [--json] | release | explain | local | none | metro.release.readiness.v1 | Print a local release readiness report for the Node package: package/install proof, publish blockers, refused assumptions, required registry/provenance/approval/versioning/integrity evidence, and disabled live/npm-registry access. | | release.artifact-manifest | metro release artifact-manifest [--json] | release | explain | local | none | metro.release.artifact-manifest.v1 | Print a local release artifact manifest describing recommended CI/release evidence files, source commands, retention ownership, blocked publish/token/registry actions, and remaining release-policy open questions without writing files. | | release.evidence-check | metro release evidence-check --dir [--json] | release | validate | local | none | metro.release.evidence-check.v1 | Validate an operator-supplied local release evidence directory against the artifact manifest by checking required files, JSON schemaVersion fields, and log file presence without writing artifacts, reading .env, loading tokens, touching npm registry state, or authorizing publish. | | release.evidence-plan | metro release evidence-plan --policy [--json] | release | explain | local | none | metro.release.evidence-plan.v1 | Plan manual release evidence capture from a validated retention policy and artifact manifest without creating directories, writing artifacts, reading .env, loading tokens, touching npm registry state, or authorizing publish. | | release.retention-policy.template | metro release retention-policy template [--json] | release | template | local | none | metro.release.retention-policy.v1 | Print a local release evidence retention policy template for documenting the reviewed artifact directory, retention period, owner, approver, access model, cleanup cadence, allowed filenames, required checks, and blocked publish/live actions before any artifact-writing command exists. | | release.retention-policy.validate | metro release retention-policy validate --file [--json] | release | validate | local | none | metro.release.retention-policy.validation.v1 | Validate a reviewed local release evidence retention policy before future artifact writers can use it, rejecting source-tree artifact directories, placeholder review fields, missing required artifact filenames, missing local checks, and missing blocked-action acknowledgements. | | source-boundary.template | metro source-boundary template [--workflow ] [--shape ] [--json] | source-boundary | explain | local | none | metro.source-boundary.v1 | Print a local manifest template for proving workflow inputs use current source files, generated artifacts as evidence-only, and no one-off command handlers. | | source-boundary.validate | metro source-boundary validate --file [--json] | source-boundary | validate | local | none | metro.source-boundary.validation.v1 | Validate local source-boundary evidence so future workflow inputs do not promote one-off scripts, depend on generated artifacts as source, or revive a previous billing system as a current integration. | | preflight.template | metro preflight template --workflow --shape [--sandbox\|--prod] [--json] | preflight | explain | local | none | metro.preflight.v1 | Print a local apply-preflight template for a supported future apply workflow. | | preflight.validate | metro preflight validate --file [--json] | preflight | validate | local | none | metro.preflight.validation.v1 | Validate an apply-preflight file before any future apply workflow can be approved. | | apply-gate.template | metro apply-gate template --workflow --shape [--sandbox\|--prod] [--json] | apply-gate | explain | local | none | metro.apply-gate.v1 | Print a local apply gate manifest tying preview hash, preflight, sandbox proof, approval, key fingerprint, audit, verification, rollback, and idempotency evidence together without enabling apply. | | apply-gate.validate | metro apply-gate validate --file [--json] | apply-gate | validate | local | none | metro.apply-gate.validation.v1 | Validate a local apply gate manifest and referenced preflight/proof files before any future apply runner can use the evidence. | | approval-record.template | metro approval-record template --apply-gate [--approval-id ] [--requested-by ] [--approved-by ] [--owner ] [--business-purpose ] [--expires-at ] [--json] | approval-record | explain | local | none | metro.workflow.approval-record.v1 | Build a durable local workflow approval record from a validated apply-gate file hash, preserving reviewed preview, preflight, sandbox proof, audit, read-back, rollback, idempotency, and owner approval evidence without serving as current-turn authorization or enabling workflow apply. | | approval-record.validate | metro approval-record validate --file [--json] | approval-record | validate | local | none | metro.workflow.approval-record.validation.v1 | Validate a durable local workflow approval record against the referenced apply-gate file hash, approval metadata, sandbox proof, audit destination, rollback, idempotency, and disabled-live-apply state before future workflow apply evidence can use it. | | apply-readback.verify | metro apply-readback verify --audit (--inspect-output \|--inspect-outputs ) [--row ] [--json] | apply-readback | verify | local | none | metro.workflow.apply-readback.verify.v1 | Compare local workflow apply audit verification checks with one or more verified inspect-output evidence files, binding read-back proof without enabling live reads, live apply, or current-turn authorization. | | audit.template | metro audit template --workflow --shape [--sandbox\|--prod] [--json] | audit | explain | local | none | metro.audit.template.v1 | Print a local JSONL audit-row template for a supported future apply workflow. | | audit.validate | metro audit validate --file [--json] | audit | validate | local | none | metro.audit.validation.v1 | Validate local audit JSONL rows for required evidence fields, hashes, verification status, and secret-free content. | | audit.write | metro audit write --file --out (--dry-run\|--write) [--json] | audit | audit | local | none | metro.audit.write.v1 | Validate and optionally append local workflow audit JSONL rows to an explicit append-only destination while workflow apply remains disabled. | | proof.sandbox-template | metro proof sandbox-template --workflow --shape [--json] | proof | explain | local | none | metro.sandbox-proof.v1 | Print a sandbox-proof manifest template for a supported future write workflow without enabling apply. | | proof.validate | metro proof validate --file [--json] | proof | validate | local | none | metro.sandbox-proof.validation.v1 | Validate a local sandbox-proof manifest for preview, preflight, audit, canary, read-back, rollback, idempotency, and production-block evidence. | | customer.billing-state.plan | metro customer billing-state --customer-id (--sandbox\|--prod) --plan [--json] | customer | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for customer billing state, including customer, billing-provider, contract, balance, and invoice endpoints. | | package.inspect.plan | metro package inspect --alias (--sandbox\|--prod) --plan [--json] | package | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for package alias inspection, package get, and contracts-on-package checks without loading a Metronome API client. | | product.inspect.plan | metro product inspect --product-id (--sandbox\|--prod) --plan [--json] | product | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for product current, initial, archived, and scheduled-update state without loading a Metronome API client. | | billing-provider.inspect.plan | metro billing-provider inspect --customer-id (--sandbox\|--prod) --plan [--json] | billing-provider | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for customer billing provider configuration without loading a Metronome API client. | | contract.inspect.plan | metro contract inspect --contract-id (--sandbox\|--prod) --plan [--at ] [--json] | contract | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for contract inspection without loading a Metronome API client. | | invoice.inspect.plan | metro invoice inspect --invoice-id (--sandbox\|--prod) --plan [--json] | invoice | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for invoice and payment inspection without loading a Metronome API client. | | subscription.history.inspect.plan | metro subscription history inspect --customer-id --contract-id --subscription-id (--sandbox\|--prod) --plan [--json] | subscription | inspect-plan | local | none | metro.inspect.plan.v1 | Build a local read plan for subscription quantity and seat history inspection without loading a Metronome API client. | | verify.inspect-output | metro verify inspect-output --file [--json] | verify | verify | local | none | metro.verify.inspect-output.v1 | Validate a local inspect output JSON file as reusable verification evidence without making live reads. | | verify.audit-log | metro verify --audit-log [--json] | verify | verify | local | none | metro.verify.audit-log.v1 | Validate a local workflow audit JSONL file, summarize write outcomes and read-back verification status, and keep live execution disabled. | | verify.apply-result | metro verify apply-result --file [--json] | verify | verify | local | none | metro.verify.apply-result.v1 | Validate a local apply result JSON file for preview hash binding, workflow evidence bundles, preflight, audit log, write summaries, read-back checks, rollback, idempotency, and secret-free evidence. | | verify.apply-result-template | metro verify apply-result-template --workflow --shape [--sandbox\|--prod] [--json] | verify | template | local | none | metro.verify.apply-result.template.v1 | Print a local workflow apply-result evidence template with required workflow evidence bundles, writes, optional skipped rows, read-back checks, and disabled live-apply state. | | ops.list | metro ops [--json] | ops | explain | local | none | metro.ops.list.v1 | Show the pack-aware one-liner cookbook for recurring ops asks (lookups, plans, credits), each mapped to the exact command for the active workspace pack. | | ops.who | metro ops who (--sandbox\|--prod) [--json] | ops | read | live-read | read | metro.ops.who.v1 | One-shot customer snapshot: resolve whatever was pasted, show active contract + credits, and print the next-step commands. Prefer this over separate resolve/billing-state/balances calls. | | ops.log | metro ops log --ask="" [--source=slack\|linear\|verbal] [--minutes=] [--file=docs/ops-log.md] [--json] | ops | template | local | none | metro.ops.log.v1 | Append an inbound one-off ask to the ops log (AGENTS.md Proof of Accuracy Rule #4) and flag ask shapes seen 3+ times as automation targets. | | ops.top | metro ops top [--file=docs/ops-log.md] [--json] | ops | explain | local | none | metro.ops.top.v1 | Rank logged ask shapes by frequency and time spent; shapes with 3+ occurrences are flagged AUTOMATE. | | customer.create.preflight | metro customer create preflight --name= --ingest-alias=[,] [--external-id= [--external-id-field=]] [--custom-fields=] [--stripe-customer-id=cus_... --stripe-collection-method=charge_automatically\|send_invoice] [--file=] (--sandbox\|--prod) [--json] | customer | preflight | pack-op | read | metro.op-plan.v1 | Plan POST /v1/customers. Proves every ingest alias is unused (the idempotency anchor; customer create has no uniqueness_key) and custom field keys exist. | | customer.create.apply | metro customer create apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | customer | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | ratecard.create.preflight | metro ratecard create preflight --file= [--allow-alias-move] (--sandbox\|--prod) [--json] | ratecard | preflight | pack-op | read | metro.op-plan.v1 | Plan rate-cards/create plus addRates (at most 100 rates per call). Refuses an existing card name or a live alias. | | ratecard.create.apply | metro ratecard create apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | ratecard | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | ratecard.add-rates.preflight | metro ratecard add-rates preflight --rate-card-id= --file= (--sandbox\|--prod) [--json] | ratecard | preflight | pack-op | read | metro.op-plan.v1 | Plan addRates on an existing card; refuses rates that already exist. | | ratecard.add-rates.apply | metro ratecard add-rates apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | ratecard | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | package.create.preflight | metro package create preflight --file= [--allow-alias-takeover] (--sandbox\|--prod) [--json] | package | preflight | pack-op | read | metro.op-plan.v1 | Plan POST /v1/packages/create from a spec; derives a uniqueness_key when omitted and refuses alias collisions. | | package.create.apply | metro package create apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | package | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | package.clone-version.preflight | metro package clone-version preflight --aliases=[,] --handoff-at= [--usage-day=CONTRACT_START\|FIRST_OF_MONTH] (--sandbox\|--prod) [--json] | package | preflight | pack-op | read | metro.op-plan.v1 | Plan a new package version behind the same alias from the handoff hour; read-back proves the alias resolves to the old version before and the new one after. | | package.clone-version.apply | metro package clone-version apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | package | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | contract.create.preflight | metro contract create preflight ((--package-alias=\|--package-id=) --starting-at=\|--file=) (--customer-id=\|--external-id=\|--ingest-alias=\|--name=) [--allow-concurrent] (--sandbox\|--prod) [--json] | contract | preflight | pack-op | read | metro.op-plan.v1 | Plan POST /v1/contracts/create from a package (pinned package_id) or a direct spec; refuses overlapping contracts. | | contract.create.apply | metro contract create apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | contract | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | subscription.add.preflight | metro subscription add preflight (--file=\|--product-id= --billing-frequency= --quantity=) [--starting-at=] (--customer-id=\|...) [--contract-id=] (--sandbox\|--prod) [--json] | subscription | preflight | pack-op | read | metro.op-plan.v1 | Plan /v2/contracts/edit add_subscriptions; requires a matching SUBSCRIPTION rate on the contract rate card. | | subscription.add.apply | metro subscription add apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | subscription | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | subscription.set-quantity.preflight | metro subscription set-quantity preflight --subscription-id= (--quantity=\|--delta=) --starting-at= (--customer-id=\|...) (--sandbox\|--prod) [--json] | subscription | preflight | pack-op | read | metro.op-plan.v1 | Plan /v2/contracts/edit update_subscriptions.quantity_updates with an absolute quantity. | | subscription.set-quantity.apply | metro subscription set-quantity apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | subscription | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | | subscription.seats.preflight | metro subscription seats preflight --subscription-id= --starting-at= [--add-seat-ids=] [--remove-seat-ids=] [--add-unassigned=] [--remove-unassigned=] (--customer-id=\|...) (--sandbox\|--prod) [--json] | subscription | preflight | pack-op | read | metro.op-plan.v1 | Plan /v2/contracts/edit update_subscriptions.seat_updates for a SEAT_BASED subscription. | | subscription.seats.apply | metro subscription seats apply --file --confirm-hash (--sandbox\|--prod) [--apply --confirm-live-apply=\|--confirm-prod-apply=] [--json] | subscription | apply | pack-op | write | metro.op-apply.v1 | Dry run by default; --apply writes with the tenant typed token, then reads back and exits 3 on any expected-vs-actual mismatch. | ## Unsupported commands | id | command | group | mode | status | apiAccess | schemaVersion | description | | --- | --- | --- | --- | --- | --- | --- | --- | | package.apply | metro package apply --shape --file (--sandbox\|--prod) [--confirm-hash ] | | apply | unsupported | write | | Apply is blocked until apply-grade payload builders, audit logs, sandbox proof, production hash confirmation, read-back verification, and a valid preflight exist. | | package.archive.apply | metro package archive apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Package archive apply is blocked until replacement alias handoff evidence, sandbox proof, audit logs, production hash confirmation, read-back verification, rollback evidence, and owner approval exist. | | customer.setup.apply | metro customer setup apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Customer setup apply is blocked until duplicate customer state, archived alias collision checks, sandbox proof, audit logs, production hash confirmation, read-back verification, invoice-side-effect proof, and owner approval exist. | | product.retire.apply | metro product retire apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Product retirement apply is blocked until inspected rate schedules, sandbox proof, audit logs, production hash confirmation, read-back verification, rollback evidence, and owner approval exist. | | rate-card.dimensional.apply | metro rate-card dimensional apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Dimensional rate-card apply is blocked until billable-metric compound group-key evidence, product duplicate-prevention evidence, sandbox canary proof, audit logs, production hash confirmation, rate schedule and invoice read-back verification, rollback evidence, and owner approval exist. | | invoice.issue-date.apply | metro invoice issue-date apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Invoice issue-date apply is blocked until draft invoice state, contract end evidence, explicit Stripe behavior, sandbox proof, audit logs, production hash confirmation, read-back verification, remediation evidence, and owner approval exist. | | subscription.contract.apply | metro subscription contract apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Direct subscription contract apply is blocked until subscription rate-card evidence, sandbox proof, audit logs, production hash confirmation, read-back verification, rollback evidence, and owner approval exist. | | usage.ingest.apply | metro usage ingest apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Usage ingest apply is blocked until preview-events proof, canary support, audit logs, production hash confirmation, read-back verification, rollback evidence, and owner approval exist. | | custom-contract.apply | metro custom-contract apply --file (--sandbox\|--prod) --confirm-hash | | apply | unsupported | write | | Custom-contract apply is blocked until inspected current state, sandbox proof, audit logs, production hash confirmation, read-back verification, rollback evidence, and owner approval exist. | | api.read.legacy-blocked | metro api read (unsupported endpoint or missing evidence) | | read | unsupported | read | | Live read requires a supported endpoint, validated read gate, confirm-live-read token, and configured tenant key. See TEAM-QUICKSTART.md. | | api.apply.legacy-blocked | metro api apply (production or unsupported endpoint) | | apply | unsupported | write | | Live apply is sandbox-only and limited to contracts.create with apply-gate and approval-record evidence. | | customer.billing-state | metro customer billing-state --customer-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live read execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | contract.inspect | metro contract inspect --contract-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live read execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | package.inspect | metro package inspect --alias (--sandbox\|--prod) | | inspect | unsupported | read | | Live package inspect execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | product.inspect | metro product inspect --product-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live product inspect execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | billing-provider.inspect | metro billing-provider inspect --customer-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live billing-provider inspect execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | invoice.inspect | metro invoice inspect --invoice-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live read execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | | subscription.history.inspect | metro subscription history inspect --customer-id --contract-id --subscription-id (--sandbox\|--prod) | | inspect | unsupported | read | | Live subscription history inspect execution is blocked until tenant-explicit guarded read clients exist. Use the --plan form for the local endpoint and output contract plan. | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Validators > The MTR validator codes and what each one checks. Source: https://metrocli.com/docs/reference/validators/ · Docs index: https://metrocli.com/llms.txt Every validator rule metro checks before a preview or apply, with severity and the fix. A failing `error` rule exits `1`. > **Source.** Generated from `metro docs validator-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.validator-reference.v1`. - schemaVersion: `metro.docs.validator-reference.v1` ## Validator rules | id | severity | message | | --- | --- | --- | | MTR-TENANT-001 | error | Choose exactly one tenant with --sandbox, --prod, or a profile that resolves to one tenant. | | MTR-TENANT-002 | error | Bind production approval to the exact reviewed preview hash before apply can proceed. | | MTR-TENANT-003 | error | Configure the profile with one explicit tenant and a matching tenant-scoped Metronome key environment variable name. | | MTR-TENANT-004 | error | Re-run preview and preflight with the current tenant key or restart approval after confirming the key change. | | MTR-ENDPOINT-001 | error | Cite endpoint-matrix and a reviewed endpoint source such as a published Metronome doc or local skill before treating the endpoint as apply evidence. | | MTR-ENDPOINT-002 | error | Use the exact method and path from the local endpoint matrix and cite the reviewed source ID that supports it. | | MTR-APIREQ-001 | error | Add the required endpoint request field or policy evidence before any preview or future live runner can use this endpoint. | | MTR-APIREQ-002 | error | Remove fields forbidden by the reviewed endpoint contract and use the endpoint-specific workflow shape when the operation needs richer policy evidence. | | MTR-APIREQ-003 | error | Remove API keys, bearer tokens, passwords, and secret-shaped fields. The CLI should reference tenant profiles and env var names, never inline secrets. | | MTR-APIREQ-004 | error | Adjust the request to match the reviewed endpoint contract and required local policy gates before any preview or future apply is considered. | | MTR-PKG-001 | error | Provide packageAlias for package-based workflows. | | MTR-PKG-002 | error | Provide a stable uniquenessKey of 128 characters or fewer. | | MTR-PKG-003 | error | Use the restricted package contract-create shape: customer_id, starting_at, package_alias or package_id, uniqueness_key, and transition only. | | MTR-PKG-004 | error | Verify the package alias resolves to the intended package at the workflow timestamp before previewing package moves or old-version archive. | | MTR-PKG-010 | error | Set creditGrantMode to monthly-drip for 1/12 credit grants or lump-sum only when finance explicitly requires legacy behavior. | | MTR-PKG-011 | error | Provide annualCreditsTotal, fixedProductId, accessCreditTypeId, and commitName for recurring_commits credit modeling. | | MTR-PKG-012 | error | Provide creditAmount (positive integer), trialDurationDays (1-365 integer), rolloverFraction (0 to 1), and accessCreditTypeId. The shape generates commit_duration.unit PERIODS, duration.value as a string, starting_at_offset, and proration automatically. | | MTR-PKG-013 | error | Set noStripeConfirmed: true to confirm this package has no billing_provider and no invoice_amount on the commit - no Stripe invoice will be generated. | | MTR-RATE-001 | error | State the current entitlement evidence and close retired product rates with entitled:false. | | MTR-RATE-002 | error | Set billingFrequency to the frequency required by the shape. | | MTR-RATE-003 | error | Close every affected rate-card entry with entitled:false and price:0 before archiving the product. | | MTR-RATE-004 | error | Provide startingAt as a UTC hour-boundary timestamp. | | MTR-RATE-005 | error | Prove the USAGE product pricing and presentation group keys are backed by one compound billable-metric group key, and provide reviewed per-dimension rate rows. | | MTR-TIME-001 | error | Use an ISO timestamp ending in :00:00Z or :00:00.000Z. | | MTR-TIME-002 | error | Use a future UTC hour-boundary timestamp for no-immediate-invoice workflows. | | MTR-TIME-004 | error | Archive an old package version only after the replacement package alias is live and verified by package read-back evidence. | | MTR-BILL-001 | error | Attach or plan a Stripe billing provider config before an invoice-producing workflow. | | MTR-BILL-002 | error | Provide exactly one of deliveryMethodId or deliveryMethod. Use deliveryMethodId for multi-entity Stripe billing, or direct_to_billing_provider for the single-entity shorthand. | | MTR-BILL-003 | error | Choose an existingConfigPolicy such as fail_if_exists or reuse_if_matching before planning attachment. | | MTR-BILL-004 | error | Set the shape-specific Stripe draft behavior field explicitly before preview. | | MTR-BILL-005 | error | Set deliveryMethodScope explicitly. For multi_entity delivery, provide matching deliveryMethodId evidence, targetStripeAccountId, accountBillingProviderReviewed: true, and endpointFieldsReviewed: true. | | MTR-SUB-001 | error | Provide an explicit subscriptions[] plan with subscription_rate, collection schedule, proration, and quantity management mode before preview. | | MTR-SUB-002 | error | Make subscription_rate.billing_frequency match the verified rate-card subscription rate frequency. | | MTR-SUB-003 | error | Use the same SubscriptionProductListItem product_id in the rate-card evidence, subscription_rate, and override specifiers. | | MTR-SUB-004 | error | For QUANTITY_ONLY provide initialQuantity. For SEAT_BASED direct contracts provide seatConfig.seatGroupKey and seatConfig.initialSeatIds. | | MTR-CUSTOM-001 | error | Provide an existing metronomeCustomerId or explicitly request createMetronomeCustomer with externalCustomerId before preview. | | MTR-CUSTOM-002 | error | Use the local direct enterprise custom-contract shape with contractType direct, explicitStartingAt, and no package fields. | | MTR-CUSTOM-003 | error | Provide explicit rate card, recurring commit, invoice, seat-limit, verification, and remediation terms before preview. | | MTR-CUST-001 | error | Provide companyName, externalCustomerId, primaryIngestAlias, and the full ingestAliases list before planning customer setup. | | MTR-CUST-002 | error | Plan customer lookup by ingest alias, review archived-customer collisions, and choose fail_if_exists or reuse_if_exact_match before customer create. | | MTR-CUST-003 | error | Declare the hierarchy mode and provide contract-level hierarchy review evidence before previewing non-standalone customer setup. | | MTR-CUST-004 | error | Approve every custom field key for the Metronome customer entity and keep each value within Metronome custom-field limits. | | MTR-INV-001 | warning | Use a future UTC hour boundary or explicitly confirm immediate invoice behavior in a later preview/apply workflow. | | MTR-INV-002 | error | Only void a reviewed invoice after proving invoice status, Stripe payment/refund handling, reconciliation plan, read-back checks, and remediation ownership. | | MTR-INV-003 | error | Use updateEndDate rather than archive for this shape and inspect current invoices before planning the move. | | MTR-INV-004 | error | Only update DRAFT invoice issue dates after invoice read-back, contract-end evidence, billing-provider review, explicit Stripe behavior, and remediation planning exist. | | MTR-INV-005 | error | Regenerate only a reviewed VOID invoice after proving correction inputs, billing-provider distribution behavior, replacement invoice read-back, and reconciliation/remediation plans. | | MTR-PAY-001 | error | Review that the invoice is FINALIZED, PLG invoicing is enabled, a billing provider is attached, and the customer payment method path is ready before attempting payment. | | MTR-PAY-002 | error | List payment attempts first and prove there is no successful payment, no conflicting in-flight attempt, and a read-back plan before retrying or canceling payment. | | MTR-PAY-003 | error | Cancel only a reviewed pending payment attempt and document customer communication, retry/remediation, and payment read-back evidence before future live execution. | | MTR-IDEMP-001 | error | Provide a deterministic contractUniquenessKey of 128 characters or fewer for successor contract creation. | | MTR-IDEMP-002 | error | Provide one stable transaction_id per event and reuse the same transaction_id for retries. | | MTR-IDEMP-003 | error | Review existing objects by stable business key before future create workflows so retries or re-runs do not create duplicate catalog objects. | | MTR-VERIFY-001 | error | Provide read-back verification for each endpoint or business effect that a future apply would change. | | MTR-VERIFY-002 | error | Provide a specific rollbackPlan describing how to recover if the move preview or future apply is wrong. | | MTR-VERIFY-003 | error | Provide a one-customer or one-event canary plan, read-back checks, and resume criteria before bulk execution. | | MTR-USAGE-001 | error | State the invoice period target, finalized-period status, preview-events requirement, and remediation path before any ingest workflow. | | MTR-USAGE-002 | error | Provide customer_id, event_type, timestamp, transaction_id, and required dimensional properties for each usage event. | | MTR-USAGE-003 | error | Provide explicit invoicePeriodTarget, canaryEventCount, and post-ingest read-back plan before bulk ingest. | | MTR-CREDIT-001 | error | Provide accessCreditTypeId for the product or access credit type. | | MTR-CREDIT-002 | error | Omit invoiceSchedule for a pure access grant, or use a fiat credit type such as USD cents for a zero-dollar audit line. | | MTR-CREDIT-003 | error | Omit invoiceSchedule, or set invoiceSchedule.auditLineIntentConfirmed to true and keep unitPriceCents at 0. | | MTR-CREDIT-004 | error | For paid credit workflows, provide a positive fiat amount in cents. Complimentary grants must use 0 when an audit line is intended. | | MTR-CREDIT-005 | error | Approve every custom field key for the target Metronome object type before including custom_fields in a preview payload. | | MTR-CREDIT-006 | error | State paid_topup_invoice_expected, paymentGateType STRIPE, explicit stripeBehavior, duplicate-name review, read-back checks, and rollback/remediation before preview. | | MTR-REPO-001 | error | Extract reusable logic into tested packages/metro-core modules and leave old one-off or quarantined scripts as evidence only. | | MTR-REPO-002 | error | Use generated artifacts only as evidence with a boundary document; cite current source files for workflow behavior. | | MTR-REPO-003 | error | Keep evidence from a previous (external) billing system historical unless the user explicitly asks for legacy migration work. | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Evidence gates > Workflow to shape to gate chain, for every write workflow. Source: https://metrocli.com/docs/reference/evidence-gates/ · Docs index: https://metrocli.com/llms.txt The evidence each preview-only write shape needs before an apply could be considered: preflight, audit, sandbox proof and apply gate. > **Source.** Generated from `metro docs evidence-gate-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.evidence-gate-reference.v1`. - schemaVersion: `metro.docs.evidence-gate-reference.v1` - apiAccess: `none` ## Summary ```json { "shapesWithWorkflowMapping": 14, "fullLocalTemplatePath": 14, "preflightOnly": 0, "notCovered": 0 } ``` ## sourceModules - `packages/metro-core/src/shapes/index.js` - `packages/metro-core/src/preflight/index.js` - `packages/metro-core/src/audit/index.js` - `packages/metro-core/src/proof/sandbox-manifest.js` - `packages/metro-core/src/apply-gate/index.js` ## gates | workflow | shape | title | family | maturity | status | fullPathAvailable | localOnly | | --- | --- | --- | --- | --- | --- | --- | --- | | customer.setup | customer-setup | Customer Setup Preview | customer | local-validated | full-local-template-path | true | true | | package.apply | pro-annual | Pro Annual Package | package | local-validated | full-local-template-path | true | true | | credit.apply | complimentary-credit-grant | Complimentary Credit Grant | credit | local-validated | full-local-template-path | true | true | | credit.apply | paid-credit-top-up | Paid Credit Top-Up | credit | local-validated | full-local-template-path | true | true | | package.archive | package-alias-archive-handoff | Package Alias Archive Handoff | package | local-validated | full-local-template-path | true | true | | billing-provider.attach | stripe-billing-provider-attachment | Stripe Billing Provider Attachment | billing-provider | local-validated | full-local-template-path | true | true | | contract.move-plan.apply | package-plan-move-no-immediate-invoice | Package Plan Move Without Immediate Invoice | contract | local-validated | full-local-template-path | true | true | | contract.move-plan.apply | package-plan-move-immediate-invoice | Package Plan Move With Immediate Plan Fee | contract | local-validated | full-local-template-path | true | true | | product.rate-retirement | product-rate-retirement | Product Rate Retirement | product | local-validated | full-local-template-path | true | true | | rate-card.dimensional.apply | dimensional-rate-card | Dimensional Rate-Card Preview | rate-card | local-validated | full-local-template-path | true | true | | invoice.issue-date-update | invoice-issue-date-update | Draft Invoice Issue-Date Update | invoice | local-validated | full-local-template-path | true | true | | subscription.contract.apply | direct-subscription-contract | Direct Subscription Contract | subscription | local-validated | full-local-template-path | true | true | | usage.ingest-preview | usage-ingest-preview | Usage Ingest Preview Plan | usage | local-validated | full-local-template-path | true | true | | custom-contract.create | enterprise-custom-contract | Enterprise Custom Contract | custom-contract | local-validated | full-local-template-path | true | true | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Shapes > The catalog of local shapes. Source: https://metrocli.com/docs/reference/shapes/ · Docs index: https://metrocli.com/llms.txt Every reviewed shape, with its family, maturity and purpose. See [Shapes and workspaces](/docs/concepts/shapes-and-workspaces). > **Source.** Generated from `metro docs shape-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.shape-reference.v1`. - schemaVersion: `metro.docs.shape-reference.v1` ## Shapes | id | family | maturity | purpose | | --- | --- | --- | --- | | customer-setup | customer | local-validated | Validate and locally preview Metronome customer creation with ingest aliases, optional Stripe billing-provider setup, customer custom fields, hierarchy posture, and read-back checks before any API client loads. | | pro-annual | package | local-validated | Validate and locally preview the input needed to create a paid annual Pro package shape before any API client loads. | | pro-annual-self-serve-v2 | package | local-validated | Validate and preview annual self-serve packages with explicit annual plan fee and creditGrantMode monthly-drip (1/12) or lump-sum recurring_commits. | | free-credit-trial | package | local-validated | Validate and locally preview the input needed to create a free-trial package with recurring credit grants, auto-expiry, and no Stripe billing before any API client loads. The shape enforces commit_duration.unit PERIODS, duration.value as a string, starting_at_offset, and proration so agents never hand-craft this payload. | | complimentary-credit-grant | credit | local-validated | Validate and locally preview a pure access grant or zero-dollar audit-line grant without loading Metronome clients. | | paid-credit-top-up | credit | local-validated | Validate and locally preview a payment-gated paid credit top-up on an existing contract without loading Metronome or Stripe clients. | | package-alias-archive-handoff | package | local-validated | Validate and locally preview archiving an old package version only after the replacement alias is already live and verified. | | stripe-billing-provider-attachment | billing-provider | local-validated | Validate and locally preview the input needed to attach Stripe billing provider configuration to an existing Metronome customer. | | package-plan-move-no-immediate-invoice | contract | local-validated | Validate and locally preview a package-based contract transition that moves a customer at a future cutover without intentionally creating an immediate invoice. | | package-plan-move-immediate-invoice | contract | local-validated | Validate and locally preview a package-based RENEWAL transition at current or past UTC hour that intentionally issues an immediate SCHEDULED plan fee (billing-day realignment, package version handoff). | | product-rate-retirement | product | local-validated | Validate and locally preview closing product rate-card entries with entitled:false and price:0 before any product archive is planned. | | dimensional-rate-card | rate-card | local-validated | Validate and locally preview one dimensional USAGE product plus per-action rate-card entries before any Metronome client loads. | | invoice-issue-date-update | invoice | local-validated | Validate and locally preview moving a DRAFT invoice issue date through the contract-scoped updateInvoiceIssueDate endpoint before any API client loads. | | direct-subscription-contract | subscription | local-validated | Validate and locally preview a direct contract with one subscription line before any API client loads. | | usage-ingest-preview | usage | local-validated | Validate and locally preview a Metronome usage event batch before any invoice preview or ingest API call can run. | | enterprise-custom-contract | custom-contract | local-validated | Validate and locally preview a direct enterprise custom contract with explicit rate card, recurring commit, Stripe billing-provider config, optional bonus commits, and optional seat assignments without loading API clients. | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Inputs > Input normalization and deterministic hashing. Source: https://metrocli.com/docs/reference/inputs/ · Docs index: https://metrocli.com/llms.txt How metro reads JSON and YAML input: the adapters, the normalized output, round-trip guarantees and the secret scan. > **Source.** Generated from `metro docs input-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.input-reference.v1`. - schemaVersion: `metro.docs.input-reference.v1` - apiAccess: `none` ## Summary ```json { "structuredInputFormatLabel": "JSON/YAML", "supportedExtensionCount": 3, "normalizationModes": [ "shape", "api-request" ], "outputSchemaVersion": "metro.input.normalize.v1", "liveApiAccess": "none" } ``` ## supportedFormats | id | extensions | parser | status | roundTripOutput | notes | | --- | --- | --- | --- | --- | --- | | json | .json | JSON.parse | supported | stable-json | JSON is the canonical machine output contract., Input object keys are sorted during canonicalization before hashing. | | yaml | .yaml, .yml | packages/metro-core/src/input/files.js parseSimpleYaml | supported-subset | stable-json | The local YAML adapter supports the reviewed fixture subset: mappings, sequences, scalars, and JSON-style inline flow values., Advanced YAML features such as anchors, tags, and multi-document streams are intentionally unsupported until a reviewed input contract needs them. | ## normalizationModes | id | command | targetType | validator | normalizedValue | nextLocalEvidence | sources | | --- | --- | --- | --- | --- | --- | --- | | shape | metro input normalize --shape --file [--json] | Workflow shape | validateShapeInput | The original structured input canonicalized with sorted object keys. | metro validate --shape --file --json | docs/metronome-cli/one-goal.md, docs/metronome-cli/SHAPE_CATALOG.md, packages/metro-core/src/input/normalize.js, packages/metro-core/src/validators/index.js | | api-request | metro input normalize --api --file [--json] | Reviewed expert API endpoint ID | validateApiEndpointRequest | The endpoint request envelope with body, query, path, evidence, and metadata keys canonicalized. | metro api validate --file --json | docs/metronome-cli/one-goal.md, docs/metronome-cli/CLI_ARCHITECTURE.md, packages/metro-core/src/input/normalize.js, packages/metro-core/src/api-catalog/validation.js | ## proofCommands - `node bin/metro.js input normalize --shape pro-annual --file --json` - `node bin/metro.js input normalize --api contracts.create --file --json` - `npm --prefix metronome-cli run test:golden` - `node docs/metronome-cli/site/verify-site.js` ## sources - `docs/metronome-cli/one-goal.md` - `docs/metronome-cli/CLI_ARCHITECTURE.md` - `docs/metronome-cli/VALIDATION_AND_GUARDRAILS.md` - `packages/metro-core/src/input/files.js` - `packages/metro-core/src/input/normalize.js` - `packages/metro-core/src/api-catalog/validation.js` ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # API catalog > The hand-curated Metronome endpoint catalog metro knows. Source: https://metrocli.com/docs/reference/api-catalog/ · Docs index: https://metrocli.com/llms.txt The Metronome endpoints metro knows, hand-curated with request and response contracts, permission scopes and gates. Metronome's docs at docs.metronome.com are the source of truth. For every documented endpoint and whether metro wraps it, see [Metronome API coverage](/docs/reference/api-coverage). > **Source.** Generated from `metro docs api-reference --markdown` in metrocli/metro @f7c4a76. Source schemaVersion: `metro.docs.api-reference.v1`. - schemaVersion: `metro.docs.api-reference.v1` - apiAccess: `none` ## Endpoints | id | family | method | path | supportStatus | apiAccess | | --- | --- | --- | --- | --- | --- | | usage.ingest | usage | POST | /v1/ingest | workflow-preview-supported | none | | usage.groups | usage | POST | /v1/usage/groups | cataloged-local-only | none | | usage.batch | usage | POST | /v1/usage | cataloged-local-only | none | | events.search | usage | POST | /v1/events/search | cataloged-local-only | none | | billableMetrics.get | billable-metrics | GET | /v1/billable-metrics/{billable_metric_id} | cataloged-local-only | none | | billableMetrics.list | billable-metrics | GET | /v1/billable-metrics | cataloged-local-only | none | | billableMetrics.create | billable-metrics | POST | /v1/billable-metrics/create | cataloged-local-only | none | | billableMetrics.update | billable-metrics | PUT | /v1/billable-metrics/{billable_metric_id} | cataloged-local-only | none | | billableMetrics.archive | billable-metrics | POST | /v1/billable-metrics/archive | cataloged-local-only | none | | packages.create | packages | POST | /v1/packages/create | workflow-preview-supported | none | | packages.get | packages | POST | /v1/packages/get | inspect-plan-supported | none | | packages.list | packages | POST | /v1/packages/list | inspect-plan-supported | none | | packages.listContractsOnPackage | packages | POST | /v1/packages/listContractsOnPackage | cataloged-local-only | none | | packages.archive | packages | POST | /v1/packages/archive | workflow-preview-supported | none | | contracts.create | contracts | POST | /v1/contracts/create | workflow-preview-supported | none | | contracts.updateEndDate | contracts | POST | /v1/contracts/updateEndDate | workflow-preview-supported | none | | contracts.get.v2 | contracts | POST | /v2/contracts/get | inspect-plan-supported | none | | contracts.list.v2 | contracts | POST | /v2/contracts/list | inspect-plan-supported | none | | contracts.getRateSchedule | contracts | POST | /v1/contracts/getContractRateSchedule | cataloged-local-only | none | | contracts.getEditHistory | contracts | POST | /v2/contracts/getEditHistory | cataloged-local-only | none | | contracts.getSubscriptionQuantityHistory | contracts | POST | /v1/contracts/getSubscriptionQuantityHistory | cataloged-local-only | none | | contracts.getSubscriptionSeatsHistory | contracts | POST | /v1/contracts/getSubscriptionSeatsHistory | cataloged-local-only | none | | contracts.edit.v2 | contracts | POST | /v2/contracts/edit | workflow-preview-supported | none | | contracts.updateInvoiceIssueDate | contracts | POST | /v1/contracts/updateInvoiceIssueDate | workflow-preview-supported | none | | commits.list | credits | POST | /v1/contracts/customerCommits/list | inspect-plan-supported | none | | credits.list | credits | POST | /v1/contracts/customerCredits/list | inspect-plan-supported | none | | customerBalances.list | credits | POST | /v1/contracts/customerBalances/list | inspect-plan-supported | none | | seatBalances.list | credits | POST | /v1/contracts/seatBalances/list | cataloged-local-only | none | | invoices.preview | invoices | POST | /v1/customers/{customer_id}/previewEvents | workflow-preview-supported | none | | customers.get | customers | GET | /v1/customers/{customer_id} | inspect-plan-supported | none | | customers.list | customers | GET | /v1/customers | local-read-plan-supported | none | | customers.create | customers | POST | /v1/customers | workflow-preview-supported | none | | customers.archive | customers | POST | /v1/customers/archive | cataloged-local-only | none | | customers.updateConfig | customers | POST | /v1/customers/{customer_id}/updateConfig | workflow-preview-supported | none | | customers.updateName | customers | POST | /v1/customers/{customer_id}/updateName | cataloged-local-only | none | | customers.setIngestAliases | customers | POST | /v1/customers/{customer_id}/setIngestAliases | cataloged-local-only | none | | invoices.listForCustomer | invoices | GET | /v1/customers/{customer_id}/invoices | inspect-plan-supported | none | | invoices.listBreakdowns | invoices | GET | /v1/customers/{customer_id}/invoices/breakdowns | cataloged-local-only | none | | invoices.get | invoices | POST | /v1/invoices/get | inspect-plan-supported | none | | invoices.void | invoices | POST | /v1/invoices/void | cataloged-local-only | none | | invoices.regenerate | invoices | POST | /v1/invoices/regenerate | cataloged-local-only | none | | payments.listForInvoice | payments | POST | /v1/invoices/payments/list | cataloged-local-only | none | | payments.attempt | payments | POST | /v1/invoices/payments/attempt | cataloged-local-only | none | | payments.cancel | payments | POST | /v1/invoices/payments/cancel | cataloged-local-only | none | | billingProvider.setCustomerConfigurations | billing-provider | POST | /v1/setCustomerBillingProviderConfigurations | workflow-preview-supported | none | | billingProvider.getCustomerConfigurations | billing-provider | POST | /v1/getCustomerBillingProviderConfigurations | inspect-plan-supported | none | | billingProvider.listConfiguredProviders | billing-provider | POST | /v1/listConfiguredBillingProviders | cataloged-local-only | none | | customFields.addKey | custom-fields | POST | /v1/customFields/addKey | cataloged-local-only | none | | customFields.removeKey | custom-fields | POST | /v1/customFields/removeKey | cataloged-local-only | none | | customFields.setValues | custom-fields | POST | /v1/customFields/setValues | cataloged-local-only | none | | customFields.deleteValues | custom-fields | POST | /v1/customFields/deleteValues | cataloged-local-only | none | | customFields.listKeys | custom-fields | POST | /v1/customFields/listKeys | cataloged-local-only | none | | settings.listPricingUnits | settings | GET | /v1/credit-types/list | cataloged-local-only | none | | security.getServices | security | GET | /v1/services | cataloged-local-only | none | | security.getAuditLogs | security | GET | /v1/auditLogs | cataloged-local-only | none | | products.get | products | POST | /v1/contract-pricing/products/get | inspect-plan-supported | none | | products.list | products | POST | /v1/contract-pricing/products/list | cataloged-local-only | none | | products.create | products | POST | /v1/contract-pricing/products/create | workflow-preview-supported | none | | products.update | products | POST | /v1/contract-pricing/products/update | workflow-preview-supported | none | | products.archive | products | POST | /v1/contract-pricing/products/archive | workflow-preview-supported | none | | rateCards.create | rate-cards | POST | /v1/contract-pricing/rate-cards/create | workflow-preview-supported | none | | rateCards.update | rate-cards | POST | /v1/contract-pricing/rate-cards/update | workflow-preview-supported | none | | rateCards.archive | rate-cards | POST | /v1/contract-pricing/rate-cards/archive | workflow-preview-supported | none | | rateCards.setProductOrder | rate-cards | POST | /v1/contract-pricing/rate-cards/setRateCardProductsOrder | workflow-preview-supported | none | | rateCards.get | rate-cards | POST | /v1/contract-pricing/rate-cards/get | cataloged-local-only | none | | rateCards.list | rate-cards | POST | /v1/contract-pricing/rate-cards/list | cataloged-local-only | none | | rateCards.getRates | rate-cards | POST | /v1/contract-pricing/rate-cards/getRates | cataloged-local-only | none | | rateCards.addRates | rate-cards | POST | /v1/contract-pricing/rate-cards/addRates | workflow-preview-supported | none | | rateCards.getRateSchedule | rate-cards | POST | /v1/contract-pricing/rate-cards/getRateSchedule | inspect-plan-supported | none | | billableMetrics.listForCustomer | billable-metrics | GET | /v1/customers/{customer_id}/billable-metrics | cataloged-local-only | none | | invoices.getForCustomer | invoices | GET | /v1/customers/{customer_id}/invoices/{invoice_id} | cataloged-local-only | none | | invoices.getPdf | invoices | GET | /v1/customers/{customer_id}/invoices/{invoice_id}/pdf | cataloged-local-only | none | | contracts.get.v1 | contracts | POST | /v1/contracts/get | cataloged-local-only | none | | contracts.list.v1 | contracts | POST | /v1/contracts/list | cataloged-local-only | none | | customerBalances.getNetBalance | credits | POST | /v1/contracts/customerBalances/getNetBalance | cataloged-local-only | none | | alerts.getForCustomer | alerts | POST | /v1/customer-alerts/get | cataloged-local-only | none | | alerts.listForCustomer | alerts | POST | /v1/customer-alerts/list | cataloged-local-only | none | | notifications.get | notifications | POST | /v2/notifications/get | cataloged-local-only | none | | notifications.listOffset | notifications | POST | /v2/notifications/offset/list | cataloged-local-only | none | | notifications.listSystem | notifications | POST | /v2/notifications/system/list | cataloged-local-only | none | | webhooks.listTriggeredNotifications | webhooks | POST | /v1/webhooks/{webhook_id}/triggered_notifications | cataloged-local-only | none | | webhooks.getTriggeredNotification | webhooks | GET | /v1/webhooks/{webhook_id}/triggered_notifications/{triggered_notification_id} | cataloged-local-only | none | ## families | family | endpointCount | operationTypes | supportStatuses | | --- | --- | --- | --- | | alerts | 2 | {"read":2} | {"cataloged-local-only":2} | | billable-metrics | 6 | {"read":3,"write":3} | {"cataloged-local-only":6} | | billing-provider | 3 | {"write":1,"read":2} | {"workflow-preview-supported":1,"inspect-plan-supported":1,"cataloged-local-only":1} | | contracts | 12 | {"write":4,"read":8} | {"workflow-preview-supported":4,"inspect-plan-supported":2,"cataloged-local-only":6} | | credits | 5 | {"read":5} | {"inspect-plan-supported":3,"cataloged-local-only":2} | | custom-fields | 5 | {"write":4,"read":1} | {"cataloged-local-only":5} | | customers | 7 | {"read":2,"write":5} | {"inspect-plan-supported":1,"local-read-plan-supported":1,"workflow-preview-supported":2,"cataloged-local-only":3} | | invoices | 8 | {"preview":1,"read":5,"write":2} | {"workflow-preview-supported":1,"inspect-plan-supported":2,"cataloged-local-only":5} | | notifications | 3 | {"read":3} | {"cataloged-local-only":3} | | packages | 5 | {"write":2,"read":3} | {"workflow-preview-supported":2,"inspect-plan-supported":2,"cataloged-local-only":1} | | payments | 3 | {"read":1,"write":2} | {"cataloged-local-only":3} | | products | 5 | {"read":2,"write":3} | {"inspect-plan-supported":1,"cataloged-local-only":1,"workflow-preview-supported":3} | | rate-cards | 9 | {"write":5,"read":4} | {"workflow-preview-supported":5,"cataloged-local-only":3,"inspect-plan-supported":1} | | security | 2 | {"read":2} | {"cataloged-local-only":2} | | settings | 1 | {"read":1} | {"cataloged-local-only":1} | | usage | 4 | {"write":1,"read":3} | {"workflow-preview-supported":1,"cataloged-local-only":3} | | webhooks | 2 | {"read":2} | {"cataloged-local-only":2} | ## writeProofLadder | order | id | readinessField | command | proves | unlocks | apiAccess | liveExecutionEnabledInCurrentCli | | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | request-validation | requestValidator | metro api validate --file [--json] | Request body, path parameters, query placement, tenant-independent endpoint shape, and secret-free input are locally valid for the reviewed endpoint ID. | local-api-preview | none | false | | 2 | local-api-preview | localPreview | metro api preview --file (--sandbox\|--prod) [--json] | The reviewed request can be normalized into a deterministic local preview with request hash, payload hash, permission scope, side-effect profile, and no live execution. | api-preflight | none | false | | 3 | api-preflight | apiPreflight | metro api preflight template --preview [--profile-resolution ] [--approval-id ] [--json] | The preview has reviewed tenant/profile binding, idempotency, audit destination, read-back plan, rollback or remediation planning, and required approval context. | api-sandbox-proof | none | false | | 4 | api-sandbox-proof | apiSandboxProof | metro api sandbox-proof template --preview --preflight [--reviewed-by ] [--owner ] [--json] | Sandbox canary, read-back, invoice behavior, rollback, and remediation evidence can be bound to the exact preview request hash before any production gate. | api-apply-gate | none | false | | 5 | api-apply-gate | apiApplyGate | metro api apply-gate template --preview --preflight [--sandbox-proof ] [--profile-resolution ] [--json] | Reviewed preview, preflight, sandbox proof, tenant profile, key fingerprint, audit destination, read-back plan, rollback or remediation plan, and idempotency review are hash-bound. | api-approval-record | none | false | | 6 | api-approval-record | apiApprovalRecord | metro api approval-record template --apply-gate [--approval-id ] [--requested-by ] [--approved-by ] [--owner ] [--business-purpose ] [--expires-at ] [--json] | A durable approval record can bind owner approval to the validated apply gate while still requiring exact current-turn authorization for any future live execution. | api-apply-audit | none | false | | 7 | api-apply-audit | apiApplyAudit | metro api apply-audit write --approval-record --out --actor (--dry-run\|--write) [--timestamp ] [--json] | A planned audit row can bind approval, tenant profile, request hash, payload hash, rollback, read-back, and idempotency evidence without capturing reusable live authorization. | api-apply-readback | none | false | | 8 | api-apply-readback | apiApplyReadback | metro api apply-readback verify --apply-audit --read-result [--row ] [--json] | Read-back evidence is compatible with the planned write endpoint, tenant, and audit row before any apply-result record claims semantic success. | api-apply-result | none | false | | 9 | api-apply-result | apiApplyResult | metro api apply-result template --apply-audit --apply-readback [--row ] [--json] | A future guarded runner result can record current-turn authorization capture, response hash, response object IDs, live audit row hash, semantic read-back success, rollback/remediation, idempotency review, and secret-free evidence. | future-guarded-apply-runner-only | none | false | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Metronome API coverage > Every endpoint documented at docs.metronome.com, linked to its page, with what metro wraps. Source: https://metrocli.com/docs/reference/api-coverage/ · Docs index: https://metrocli.com/llms.txt metro does not copy Metronome's API reference. Metronome's docs are the source of truth for every endpoint, field and response, and they change without notice, so every row below links to the live page on docs.metronome.com (add `.md` to any page URL for markdown). This page shows only what metro wraps: **op** means a metro command calls the endpoint live (writes only through preview, confirm hash, sandbox-first apply and readback); **catalog read** and **catalog write** mean metro has a reviewed contract you can read with `metro api explain `, with writes kept to local preview; **not yet** means read Metronome's page and do it there. The list is re-checked against Metronome's docs every week, and a change opens an issue on the metro repo. Checked **2026-11-03** against https://docs.metronome.com/llms-full.txt: 108 documented endpoints. metro covers 80 (op 27, catalog read 31, catalog write 22); 28 are not yet wrapped. | Endpoint | Metronome page | metro status | metro command | |---|---|---|---| | `POST /v1/alerts/archive` | [Archive a threshold notification](https://docs.metronome.com/api-reference/alerts/archive-a-threshold-notification) | not-yet | none | | `POST /v1/alerts/create` | [Create a threshold notification](https://docs.metronome.com/api-reference/alerts/create-a-threshold-notification) | not-yet | none | | `POST /v1/customer-alerts/get` | [Get a threshold notification](https://docs.metronome.com/api-reference/alerts/get-a-threshold-notification) | catalog-read (`alerts.getForCustomer`) | `metro api explain alerts.getForCustomer` | | `POST /v1/customer-alerts/list` | [Get all threshold notifications](https://docs.metronome.com/api-reference/alerts/get-all-threshold-notifications) | catalog-read (`alerts.listForCustomer`) | `metro api explain alerts.listForCustomer` | | `POST /v1/customer-alerts/reset` | [Reset a threshold notification](https://docs.metronome.com/api-reference/alerts/reset-a-threshold-notification) | not-yet | none | | `GET /v1/billable-metrics` | [List all billable metrics](https://docs.metronome.com/api-reference/billable-metrics/list-all-billable-metrics) | catalog-read (`billableMetrics.list`) | `metro api explain billableMetrics.list` | | `GET /v1/billable-metrics/{billable_metric_id}` | [Get a billable metric](https://docs.metronome.com/api-reference/billable-metrics/get-a-billable-metric) | catalog-read (`billableMetrics.get`) | `metro api explain billableMetrics.get` | | `PUT /v1/billable-metrics/{billable_metric_id}` | [Update a billable metric](https://docs.metronome.com/api-reference/billable-metrics/update-a-billable-metric) | catalog-write (`billableMetrics.update`) | `metro api explain billableMetrics.update` | | `POST /v1/billable-metrics/archive` | [Archive a billable metric](https://docs.metronome.com/api-reference/billable-metrics/archive-a-billable-metric) | catalog-write (`billableMetrics.archive`) | `metro api explain billableMetrics.archive` | | `POST /v1/billable-metrics/create` | [Create a billable metric](https://docs.metronome.com/api-reference/billable-metrics/create-a-billable-metric) | catalog-write (`billableMetrics.create`) | `metro api explain billableMetrics.create` | | `GET /v1/customers/{customer_id}/billable-metrics` | [Get billable metrics for a customer](https://docs.metronome.com/api-reference/billable-metrics/get-billable-metrics-for-a-customer) | catalog-read (`billableMetrics.listForCustomer`) | `metro api explain billableMetrics.listForCustomer` | | `POST /v1/contracts/amend` | [Amend a contract](https://docs.metronome.com/api-reference/contracts/amend-a-contract) | not-yet | none | | `POST /v1/contracts/archive` | [Archive a contract](https://docs.metronome.com/api-reference/contracts/archive-a-contract) | op | `metro contract repair-accidental` | | `POST /v1/contracts/create` | [Create a contract](https://docs.metronome.com/api-reference/contracts/create-a-contract) | op (`contracts.create`) | `metro contract create`, `metro contract move-plan`, `metro contract move-plan preview`, `metro subscription contract preview` | | `POST /v1/contracts/createHistoricalInvoices` | [Create historical invoices](https://docs.metronome.com/api-reference/contracts/create-historical-invoices) | not-yet | none | | `POST /v1/contracts/get` | [Get a contract (v1)](https://docs.metronome.com/api-reference/contracts/get-a-contract-v1) | catalog-read (`contracts.get.v1`) | `metro api explain contracts.get.v1` | | `POST /v1/contracts/getContractRateSchedule` | [Get the rate schedule for a contract](https://docs.metronome.com/api-reference/contracts/get-the-rate-schedule-for-a-contract) | catalog-read (`contracts.getRateSchedule`) | `metro api explain contracts.getRateSchedule` | | `POST /v1/contracts/getSubscriptionQuantityHistory` | [Get subscription quantity history](https://docs.metronome.com/api-reference/contracts/get-subscription-quantity-history) | catalog-read (`contracts.getSubscriptionQuantityHistory`) | `metro api read-plan contracts.getSubscriptionQuantityHistory` | | `POST /v1/contracts/getSubscriptionSeatsHistory` | [Get subscription seats history](https://docs.metronome.com/api-reference/contracts/get-subscription-seats-history) | op (`contracts.getSubscriptionSeatsHistory`) | `metro subscription seats`, `metro api read-plan contracts.getSubscriptionSeatsHistory` | | `POST /v1/contracts/list` | [List customer contracts (v1)](https://docs.metronome.com/api-reference/contracts/list-customer-contracts-v1) | catalog-read (`contracts.list.v1`) | `metro api explain contracts.list.v1` | | `POST /v1/contracts/setUsageFilter` | [Set a contract usage filter](https://docs.metronome.com/api-reference/contracts/set-a-contract-usage-filter) | not-yet | none | | `POST /v1/contracts/updateEndDate` | [Update the contract end date](https://docs.metronome.com/api-reference/contracts/update-the-contract-end-date) | op (`contracts.updateEndDate`) | `metro contract expire`, `metro contract extend-trial`, `metro contract move-plan`, `metro contract repair-accidental`, `metro contract move-plan preview` | | `POST /v1/contracts/updateInvoiceIssueDate` | [Update invoice issue date](https://docs.metronome.com/api-reference/contracts/update-invoice-issue-date) | catalog-write (`contracts.updateInvoiceIssueDate`) | `metro invoice issue-date preview` | | `POST /v1/packages/create` | [Create a package](https://docs.metronome.com/api-reference/contracts/create-a-package) | op (`packages.create`) | `metro package clone-version`, `metro package create`, `metro package preview` | | `POST /v1/packages/listContractsOnPackage` | [List contracts associated with a package](https://docs.metronome.com/api-reference/contracts/list-contracts-associated-with-a-package) | op (`packages.listContractsOnPackage`) | `metro package customers`, `metro api read-plan packages.listContractsOnPackage` | | `POST /v2/contracts/edit` | [Edit a contract](https://docs.metronome.com/api-reference/contracts/edit-a-contract) | op (`contracts.edit.v2`) | `metro ledger-adjustment`, `metro subscription add`, `metro subscription seats`, `metro subscription set-quantity`, `metro credit preview` | | `POST /v2/contracts/get` | [Get a contract (v2)](https://docs.metronome.com/api-reference/contracts/get-a-contract-v2) | op (`contracts.get.v2`) | `metro contract create`, `metro contract expire`, `metro contract extend-trial`, `metro contract move-plan`, `metro ledger-adjustment`, `metro subscription add`, `metro subscription seats`, `metro subscription set-quantity`, `metro contract inspect` | | `POST /v2/contracts/getEditHistory` | [Get contract edit history](https://docs.metronome.com/api-reference/contracts/get-contract-edit-history) | catalog-read (`contracts.getEditHistory`) | `metro api read-plan contracts.getEditHistory` | | `POST /v2/contracts/list` | [List customer contracts (v2)](https://docs.metronome.com/api-reference/contracts/list-customer-contracts-v2) | op (`contracts.list.v2`) | `metro contract create`, `metro contract expire`, `metro contract extend-trial`, `metro contract move-plan`, `metro contract repair-accidental`, `metro customer balances`, `metro ledger-adjustment`, `metro subscription add`, `metro subscription seats`, `metro subscription set-quantity`, `metro customer billing-state` | | `POST /v1/contracts/addManualBalanceLedgerEntry` | [Add a manual balance entry](https://docs.metronome.com/api-reference/credits-and-commits/add-a-manual-balance-entry) | op | `metro ledger-adjustment` | | `POST /v1/contracts/commits/disableTrueup` | [Disable trueup for commit](https://docs.metronome.com/api-reference/credits-and-commits/disable-trueup-for-commit) | not-yet | none | | `POST /v1/contracts/commits/threshold-billing/release` | [Release external payment gate threshold commit](https://docs.metronome.com/api-reference/credits-and-commits/release-external-payment-gate-threshold-commit) | not-yet | none | | `POST /v1/contracts/customerBalances/getNetBalance` | [Get the net balance of a customer](https://docs.metronome.com/api-reference/credits-and-commits/get-the-net-balance-of-a-customer) | op (`customerBalances.getNetBalance`) | `metro customer balances`, `metro ledger-adjustment` | | `POST /v1/contracts/customerBalances/list` | [List balances](https://docs.metronome.com/api-reference/credits-and-commits/list-balances) | op (`customerBalances.list`) | `metro contract move-plan`, `metro customer balances`, `metro ledger-adjustment`, `metro customer billing-state` | | `POST /v1/contracts/customerCommits/create` | [Create a commit](https://docs.metronome.com/api-reference/credits-and-commits/create-a-commit) | not-yet | none | | `POST /v1/contracts/customerCommits/list` | [List commits](https://docs.metronome.com/api-reference/credits-and-commits/list-commits) | catalog-read (`commits.list`) | `metro customer billing-state` | | `POST /v1/contracts/customerCommits/updateEndDate` | [Update the commit end date](https://docs.metronome.com/api-reference/credits-and-commits/update-the-commit-end-date) | not-yet | none | | `POST /v1/contracts/customerCredits/create` | [Create a credit](https://docs.metronome.com/api-reference/credits-and-commits/create-a-credit) | not-yet | none | | `POST /v1/contracts/customerCredits/list` | [List credits](https://docs.metronome.com/api-reference/credits-and-commits/list-credits) | catalog-read (`credits.list`) | `metro customer billing-state` | | `POST /v1/contracts/customerCredits/updateEndDate` | [Update the credit end date](https://docs.metronome.com/api-reference/credits-and-commits/update-the-credit-end-date) | not-yet | none | | `POST /v1/contracts/seatBalances/list` | [List seat balances](https://docs.metronome.com/api-reference/credits-and-commits/list-seat-balances) | catalog-read (`seatBalances.list`) | `metro api read-plan seatBalances.list` | | `POST /v2/contracts/commits/archive` | [Archive a commit](https://docs.metronome.com/api-reference/credits-and-commits/archive-a-commit) | not-yet | none | | `POST /v2/contracts/commits/edit` | [Edit a commit](https://docs.metronome.com/api-reference/credits-and-commits/edit-a-commit) | not-yet | none | | `POST /v2/contracts/credits/archive` | [Archive a credit](https://docs.metronome.com/api-reference/credits-and-commits/archive-a-credit) | not-yet | none | | `POST /v2/contracts/credits/edit` | [Edit a credit](https://docs.metronome.com/api-reference/credits-and-commits/edit-a-credit) | not-yet | none | | `POST /v1/customFields/addKey` | [Create a custom field key](https://docs.metronome.com/api-reference/custom-fields/create-a-custom-field-key) | catalog-write (`customFields.addKey`) | `metro api explain customFields.addKey` | | `POST /v1/customFields/deleteValues` | [Delete custom fields](https://docs.metronome.com/api-reference/custom-fields/delete-custom-fields) | catalog-write (`customFields.deleteValues`) | `metro api explain customFields.deleteValues` | | `POST /v1/customFields/listKeys` | [List custom field keys](https://docs.metronome.com/api-reference/custom-fields/list-custom-field-keys) | op (`customFields.listKeys`) | `metro customer create` | | `POST /v1/customFields/removeKey` | [Delete a custom field key](https://docs.metronome.com/api-reference/custom-fields/delete-a-custom-field-key) | catalog-write (`customFields.removeKey`) | `metro api explain customFields.removeKey` | | `POST /v1/customFields/setValues` | [Set custom field values](https://docs.metronome.com/api-reference/custom-fields/set-custom-field-values) | catalog-write (`customFields.setValues`) | `metro api explain customFields.setValues` | | `POST /v1/archiveCustomerBillingProviderConfigurations` | [Archive billing provider configurations for a customer](https://docs.metronome.com/api-reference/customers/archive-billing-provider-configurations-for-a-customer) | op | `metro billing-provider cutover` | | `GET /v1/customers` | [List customers](https://docs.metronome.com/api-reference/customers/list-customers) | op (`customers.list`) | `metro customer create`, `metro api read-plan customers.list` | | `POST /v1/customers` | [Create a customer](https://docs.metronome.com/api-reference/customers/create-a-customer) | op (`customers.create`) | `metro customer create`, `metro customer setup preview` | | `GET /v1/customers/{customer_id}` | [Get a customer](https://docs.metronome.com/api-reference/customers/get-a-customer) | catalog-read (`customers.get`) | `metro customer billing-state` | | `POST /v1/customers/{customer_id}/setIngestAliases` | [Create or update customer ingest aliases](https://docs.metronome.com/api-reference/customers/create-or-update-customer-ingest-aliases) | catalog-write (`customers.setIngestAliases`) | `metro api explain customers.setIngestAliases` | | `POST /v1/customers/{customer_id}/setName` | [Update a customer name](https://docs.metronome.com/api-reference/customers/update-a-customer-name) | not-yet | none | | `POST /v1/customers/{customer_id}/updateConfig` | [Update a customer configuration](https://docs.metronome.com/api-reference/customers/update-a-customer-configuration) | catalog-write (`customers.updateConfig`) | `metro customer setup preview` | | `POST /v1/customers/archive` | [Archive a customer](https://docs.metronome.com/api-reference/customers/archive-a-customer) | catalog-write (`customers.archive`) | `metro api explain customers.archive` | | `POST /v1/dashboards/getEmbeddableUrl` | [Get an embeddable customer dashboard](https://docs.metronome.com/api-reference/customers/get-an-embeddable-customer-dashboard) | not-yet | none | | `POST /v1/getCustomerBillingProviderConfigurations` | [Fetch billing provider configurations for a customer](https://docs.metronome.com/api-reference/customers/fetch-billing-provider-configurations-for-a-customer) | op (`billingProvider.getCustomerConfigurations`) | `metro billing-provider cutover`, `metro customer create`, `metro billing-provider inspect` | | `POST /v1/setCustomerBillingProviderConfigurations` | [Set billing provider configurations for a customer](https://docs.metronome.com/api-reference/customers/set-billing-provider-configurations-for-a-customer) | op (`billingProvider.setCustomerConfigurations`) | `metro billing-provider cutover`, `metro billing-provider preview` | | `GET /v1/customers/{customer_id}/invoices` | [List invoices](https://docs.metronome.com/api-reference/invoices/list-invoices) | op (`invoices.listForCustomer`) | `metro contract move-plan`, `metro contract repair-accidental`, `metro customer billing-state`, `metro invoice inspect` | | `GET /v1/customers/{customer_id}/invoices/{invoice_id}` | [Get an invoice](https://docs.metronome.com/api-reference/invoices/get-an-invoice) | catalog-read (`invoices.getForCustomer`) | `metro api explain invoices.getForCustomer` | | `GET /v1/customers/{customer_id}/invoices/{invoice_id}/pdf` | [Get an invoice PDF](https://docs.metronome.com/api-reference/invoices/get-an-invoice-pdf) | catalog-read (`invoices.getPdf`) | `metro api explain invoices.getPdf` | | `GET /v1/customers/{customer_id}/invoices/breakdowns` | [List invoice breakdowns](https://docs.metronome.com/api-reference/invoices/list-invoice-breakdowns) | catalog-read (`invoices.listBreakdowns`) | `metro api read-plan invoices.listBreakdowns` | | `POST /v1/customers/{customer_id}/previewEvents` | [Preview events](https://docs.metronome.com/api-reference/invoices/preview-events) | catalog-write (`invoices.preview`) | `metro usage ingest preview` | | `POST /v1/invoices/regenerate` | [Regenerate an invoice](https://docs.metronome.com/api-reference/invoices/regenerate-an-invoice) | catalog-write (`invoices.regenerate`) | `metro api explain invoices.regenerate` | | `POST /v1/invoices/void` | [Void an invoice](https://docs.metronome.com/api-reference/invoices/void-an-invoice) | catalog-write (`invoices.void`) | `metro api explain invoices.void` | | `POST /v2/notifications/archive` | [Archive an offset lifecycle event notification configuration](https://docs.metronome.com/api-reference/notifications/archive-an-offset-lifecycle-event-notification-configuration) | not-yet | none | | `POST /v2/notifications/create` | [Create an offset lifecycle event notification configuration](https://docs.metronome.com/api-reference/notifications/create-an-offset-lifecycle-event-notification-configuration) | not-yet | none | | `POST /v2/notifications/edit` | [Edit an offset or system notification](https://docs.metronome.com/api-reference/notifications/edit-an-offset-or-system-notification) | not-yet | none | | `POST /v2/notifications/get` | [Get an offset lifecycle event notification configuration](https://docs.metronome.com/api-reference/notifications/get-an-offset-lifecycle-event-notification-configuration) | catalog-read (`notifications.get`) | `metro api explain notifications.get` | | `POST /v2/notifications/offset/list` | [List offset lifecycle event notification configurations](https://docs.metronome.com/api-reference/notifications/list-offset-lifecycle-event-notification-configurations) | catalog-read (`notifications.listOffset`) | `metro api explain notifications.listOffset` | | `POST /v2/notifications/system/list` | [List system notification types](https://docs.metronome.com/api-reference/notifications/list-system-notification-types) | catalog-read (`notifications.listSystem`) | `metro api explain notifications.listSystem` | | `POST /v1/packages/list` | [List all packages](https://docs.metronome.com/api-reference/list-all-packages) | op (`packages.list`) | `metro contract create`, `metro contract move-plan`, `metro package clone-version`, `metro package create`, `metro package customers`, `metro package inspect` | | `POST /v1/packages/archive` | [Archive a package](https://docs.metronome.com/api-reference/packages/archive-a-package) | catalog-write (`packages.archive`) | `metro package archive preview` | | `POST /v1/packages/get` | [Get a package](https://docs.metronome.com/api-reference/packages/get-a-package) | op (`packages.get`) | `metro contract create`, `metro contract move-plan`, `metro package clone-version`, `metro package create`, `metro package customers`, `metro package inspect` | | `POST /v1/contract-pricing/products/archive` | [Archive a product](https://docs.metronome.com/api-reference/products/archive-a-product) | catalog-write (`products.archive`) | `metro product retire preview`, `metro rate-card dimensional preview` | | `POST /v1/contract-pricing/products/create` | [Create a product](https://docs.metronome.com/api-reference/products/create-a-product) | catalog-write (`products.create`) | `metro rate-card dimensional preview` | | `POST /v1/contract-pricing/products/get` | [Get a product](https://docs.metronome.com/api-reference/products/get-a-product) | op (`products.get`) | `metro dimensional new-code`, `metro ratecard add-rates`, `metro ratecard create`, `metro subscription add`, `metro product inspect` | | `POST /v1/contract-pricing/products/list` | [List products](https://docs.metronome.com/api-reference/products/list-products) | catalog-read (`products.list`) | `metro api explain products.list` | | `POST /v1/contract-pricing/products/update` | [Update a product](https://docs.metronome.com/api-reference/products/update-a-product) | catalog-write (`products.update`) | `metro api explain products.update` | | `POST /v1/contract-pricing/rate-cards/addRate` | [Add a rate](https://docs.metronome.com/api-reference/rate-cards/add-a-rate) | not-yet | none | | `POST /v1/contract-pricing/rate-cards/addRates` | [Add rates](https://docs.metronome.com/api-reference/rate-cards/add-rates) | op (`rateCards.addRates`) | `metro dimensional new-code`, `metro ratecard add-rates`, `metro ratecard create`, `metro product retire preview` | | `POST /v1/contract-pricing/rate-cards/archive` | [Archive a rate card](https://docs.metronome.com/api-reference/rate-cards/archive-a-rate-card) | catalog-write (`rateCards.archive`) | `metro api explain rateCards.archive` | | `POST /v1/contract-pricing/rate-cards/create` | [Create a rate card](https://docs.metronome.com/api-reference/rate-cards/create-a-rate-card) | op (`rateCards.create`) | `metro ratecard create` | | `POST /v1/contract-pricing/rate-cards/get` | [Get a rate card](https://docs.metronome.com/api-reference/rate-cards/get-a-rate-card) | op (`rateCards.get`) | `metro contract create`, `metro dimensional new-code`, `metro package create`, `metro ratecard add-rates`, `metro ratecard create` | | `POST /v1/contract-pricing/rate-cards/getRates` | [Get rates](https://docs.metronome.com/api-reference/rate-cards/get-rates) | op (`rateCards.getRates`) | `metro ratecard add-rates`, `metro ratecard create`, `metro subscription add` | | `POST /v1/contract-pricing/rate-cards/getRateSchedule` | [Get a rate schedule](https://docs.metronome.com/api-reference/rate-cards/get-a-rate-schedule) | catalog-read (`rateCards.getRateSchedule`) | `metro product inspect` | | `POST /v1/contract-pricing/rate-cards/list` | [List rate cards](https://docs.metronome.com/api-reference/rate-cards/list-rate-cards) | op (`rateCards.list`) | `metro ratecard create` | | `POST /v1/contract-pricing/rate-cards/moveRateCardProducts` | [Update the rate card products order](https://docs.metronome.com/api-reference/rate-cards/update-the-rate-card-products-order) | not-yet | none | | `POST /v1/contract-pricing/rate-cards/setRateCardProductsOrder` | [Set the rate card products order](https://docs.metronome.com/api-reference/rate-cards/set-the-rate-card-products-order) | catalog-write (`rateCards.setProductOrder`) | `metro api explain rateCards.setProductOrder` | | `POST /v1/contract-pricing/rate-cards/update` | [Update a rate card](https://docs.metronome.com/api-reference/rate-cards/update-a-rate-card) | catalog-write (`rateCards.update`) | `metro api explain rateCards.update` | | `GET /v1/auditLogs` | [Get audit logs](https://docs.metronome.com/api-reference/security/get-audit-logs) | catalog-read (`security.getAuditLogs`) | `metro api explain security.getAuditLogs` | | `GET /v1/services` | [Get services](https://docs.metronome.com/api-reference/security/get-services) | catalog-read (`security.getServices`) | `metro api explain security.getServices` | | `POST /v1/credit-types/archive` | [Archive a pricing unit](https://docs.metronome.com/api-reference/settings/archive-a-pricing-unit) | not-yet | none | | `POST /v1/credit-types/create` | [Create a pricing unit](https://docs.metronome.com/api-reference/settings/create-a-pricing-unit) | not-yet | none | | `GET /v1/credit-types/list` | [List pricing units](https://docs.metronome.com/api-reference/settings/list-pricing-units) | catalog-read (`settings.listPricingUnits`) | `metro api explain settings.listPricingUnits` | | `POST /v1/listConfiguredBillingProviders` | [List account-level billing providers](https://docs.metronome.com/api-reference/settings/list-account-level-billing-providers) | catalog-read (`billingProvider.listConfiguredProviders`) | `metro api explain billingProvider.listConfiguredProviders` | | `POST /v1/setUpBillingProvider` | [Set up account-level billing provider](https://docs.metronome.com/api-reference/settings/set-up-account-level-billing-provider) | not-yet | none | | `POST /v1/upsertAnrokApiToken` | [Upsert Anrok API token](https://docs.metronome.com/api-reference/settings/upsert-anrok-api-token) | not-yet | none | | `POST /v1/upsertAvalaraCredentials` | [Upsert Avalara credentials](https://docs.metronome.com/api-reference/settings/upsert-avalara-credentials) | not-yet | none | | `POST /v1/events/search` | [Search events](https://docs.metronome.com/api-reference/usage/search-events) | catalog-read (`events.search`) | `metro api explain events.search` | | `POST /v1/ingest` | [Ingest events](https://docs.metronome.com/api-reference/usage/ingest-events) | catalog-write (`usage.ingest`) | `metro usage ingest preview` | | `POST /v1/usage` | [Get batched usage data](https://docs.metronome.com/api-reference/usage/get-batched-usage-data) | catalog-read (`usage.batch`) | `metro api explain usage.batch` | | `POST /v1/usage/groups` | [Get usage data with paginated groupings](https://docs.metronome.com/api-reference/usage/get-usage-data-with-paginated-groupings) | catalog-read (`usage.groups`) | `metro api explain usage.groups` | | `POST /v1/webhooks/{webhook_id}/triggered_notifications` | [List triggered notifications by webhook](https://docs.metronome.com/api-reference/webhooks/list-triggered-notifications-by-webhook) | catalog-read (`webhooks.listTriggeredNotifications`) | `metro api explain webhooks.listTriggeredNotifications` | | `GET /v1/webhooks/{webhook_id}/triggered_notifications/{triggered_notification_id}` | [Get Triggered Notification and Delivery Attempts](https://docs.metronome.com/api-reference/webhooks/get-triggered-notification-and-delivery-attempts) | catalog-read (`webhooks.getTriggeredNotification`) | `metro api explain webhooks.getTriggeredNotification` | Agents: Metronome's machine-readable index is [docs.metronome.com/llms.txt](https://docs.metronome.com/llms.txt). The same data as JSON ships with metro at `docs/metronome-cli/API_COVERAGE.json`. --- # Explain > The topics behind metro docs explain. Source: https://metrocli.com/docs/reference/explain/ · Docs index: https://metrocli.com/llms.txt Topics for `metro docs explain --markdown`: decision trees for agents, plus lookups for commands, shapes, rules, gotchas and scopes. > **Source.** Generated from `metro docs explain --list --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.explain.index.v1`. - schemaVersion: `metro.docs.explain.index.v1` - apiAccess: `none` - nextSafeStep: Run metro docs explain --json for a single topic, or use explicit prefixes such as command:, shape:, gotcha:, rule:, scope:, policy:, and example: to avoid ambiguous IDs. This index does not authorize live reads or writes. ## Summary ```json { "operatingTopicCount": 14, "lookupKindCount": 8, "genericExplainableCount": 425, "liveApiAccess": "none" } ``` ## Operating topics (agent decision trees) | id | status | apiAccess | summary | explain | | --- | --- | --- | --- | --- | | first-safe-preview | local-install-backed | none | Give a new authorized teammate or internal agent one terminal-native path to prove installability, command discovery, profile shape, local validation, and sandbox-labeled preview without live API access. | metro docs explain first-safe-preview --json | | install.troubleshooting | local-install-backed | none | Use this topic when npm packaging, global installation, or the installed metro binary fails: prove the package manifest, runtime file allowlist, executable bin, temporary-prefix install, and local-only smoke command before moving to setup profiles or safe preview work. | metro docs explain install.troubleshooting --json | | package.publish-readiness | blocked-open-questions | none | Use this topic before treating the local tarball install path as an internal npm release: current proof covers npm pack contents and a temporary-prefix metro install, while registry publishing, release provenance, approval ownership, and signing or equivalent integrity evidence remain explicit blockers. | metro docs explain package.publish-readiness --json | | ci.local-checks | local-proof-backed | none | Use this topic when wiring metro into CI or agent automation: run package, install, unit, golden, site, syntax, and secret-scan checks that need no API keys, then parse metro JSON contracts instead of scraping prose. | metro docs explain ci.local-checks --json | | setup.troubleshooting | local-proof-backed | none | Use this topic when the first safe preview path, local profile doctor, or profile resolution fails: keep setup local-only, inspect schemaVersion and findings, fix the profile file or non-secret fingerprint, then rerun setup doctor and setup resolve before using profile evidence in read-gate or preflight manifests. | metro docs explain setup.troubleshooting --json | | input.normalize | local-proof-backed | none | Use metro input normalize to turn local JSON/YAML workflow shape inputs and reviewed expert API request envelopes into stable canonical JSON, validation findings, and deterministic hashes before preview, proof, or future apply work. | metro docs explain input.normalize --json | | output.anatomy | local-proof-backed | none | Use this topic to read metro JSON output consistently: identify the schema version first, check live-execution flags and API access, inspect status/refusal fields, then follow generatedFrom, sourceIds, sources, payload hashes, and nextSafeStep before using the output as local evidence. | metro docs explain output.anatomy --json | | refusal.troubleshooting | local-proof-backed | none | Use this topic when metro refuses a live read, live apply, unsupported workflow apply, or unsafe input: keep the refusal as a safety signal, identify the schema and blocked command, then gather the local preview, preflight, gate, audit, read-back, and approval evidence named by nextSafeStep before retrying any narrower local command. | metro docs explain refusal.troubleshooting --json | | billing-provider.attachment | local-preview-backed | none | Use the local Stripe billing-provider attachment shape to validate delivery method scope, existing configuration policy, Stripe draft behavior, and read-back evidence before any future customer billing-provider write is considered. | metro docs explain billing-provider.attachment --json | | customer.setup | local-preview-backed | none | Use the local customer-setup shape to validate customer identity, ingest alias collision review, optional Stripe billing-provider configuration, customer configuration, read-back checks, and rollback planning before any customer create workflow is considered. | metro docs explain customer.setup --json | | credits.product.decision | local-preview-backed | none | When someone says "add a credits product", stop and classify before creating Metronome objects. Most asks are (A) a new pricing dimension on an existing USAGE product, (B) a credit grant on an existing contract, (C) credits inside a package commit schedule, or rarely (D) a greenfield USAGE product + billable metric. Do not create products or billable metrics for new action codes. | metro docs explain credits.product.decision --json | | workspace.routing | local-preview-backed | none | Use metro workspace explain, metro plan , and metro route --goal to pick optimal shapes, refuse suboptimal API paths (e.g. products.create for a new action code), and bind sandbox/production via tenant profiles. For ambiguous "credits product" asks start with metro docs explain credits.product.decision --markdown. | metro docs explain workspace.routing --json | | contract-overrides.inspection | local-proof-backed | none | Use contracts.getRateSchedule for customer-specific contract prices that must include contract-level overrides; use rateCards.getRates for rate-card source prices before customer contract overrides. | metro docs explain contract-overrides.inspection --json | | product-rate-retirement.readback | local-proof-backed | none | Use rateCards.addRates only as a reviewed future write for closing rates; verify product retirement with rateCards.getRates, rateCards.getRateSchedule, products.get, and invoice-impact evidence before any product archive is considered. | metro docs explain product-rate-retirement.readback --json | ## Lookup kinds | kind | count | description | examples | | --- | --- | --- | --- | | api-endpoint | 69 | Reviewed Metronome endpoint IDs from the local expert API catalog. | usage.ingest, usage.groups, usage.batch, events.search | | api-family | 14 | Endpoint-family summaries derived from the reviewed API catalog. | billable-metrics, billing-provider, contracts, credits | | command | 166 | Supported local command metadata from the command catalog. | command:input.normalize, command:docs.explain, command:api.read-plan | | shape | 16 | Workflow shape summaries and validator links from the shape catalog. | shape:customer-setup, shape:pro-annual, shape:pro-annual-self-serve-v2, shape:free-credit-trial | | validator-rule | 68 | Validator rules, severities, and remediation guidance. | MTR-TENANT-001, MTR-TENANT-002, MTR-TENANT-003, MTR-TENANT-004 | | gotcha | 59 | Known failure modes from the gotcha register. | gotcha:tenant-selected-by-key, gotcha:env-file-not-authorization, gotcha:never-infer-production-from-key-presence, gotcha:fingerprints-not-key-values | | permission-scope | 25 | Permission scopes and owner/approval policy requirements. | metronome:billable-metrics:read, metronome:billable-metrics:write, metronome:billing-provider:read, metronome:billing-provider:write | | example-fixture | 8 | Checked command/output fixtures used as local proof examples. | example:api.catalog.contracts, example:api.explain.contracts-create, example:api.search.contract-create, example:api.diff.contracts-create-vs-update-end-date | ## sourceIds - `credits-product-decision` - `danger-zone` - `endpoint-matrix` - `example:api.catalog.contracts` - `example:api.explain.contracts-create` - `example:api.preflight.contracts-create` - `example:api.preview.contracts-create` - `example:api.readiness` - `local-probe-prod-all-rates` - `metro-api-preview-golden` - `metro-api-read-audit-products-get-fixture` - `metro-api-read-audit-products-get-golden` - `metro-api-read-audit-rate-cards-get-rates-fixture` - `metro-api-read-audit-rate-cards-get-rates-golden` - `metro-api-read-mock-contracts-rate-schedule-golden` - `metro-api-read-mock-rate-cards-get-rates-golden` - `metro-api-read-pipeline-contracts-rate-schedule-golden` - `metro-api-read-pipeline-golden` - `metro-api-read-pipeline-products-get-golden` - `metro-api-read-pipeline-rate-card-schedule-golden` - `metro-api-read-pipeline-rate-cards-get-rates-golden` - `metro-api-read-plan-golden-contracts-rate-schedule` - `metro-api-read-plan-golden-products-get` - `metro-api-read-plan-golden-rate-card-schedule` - `metro-api-read-plan-golden-rate-cards-get-rates` - `metro-api-read-refusal-golden` - `metro-api-readiness-golden` - `metro-api-readiness-summary-golden` - `metro-billing-provider-attach-fixture` - `metro-billing-provider-inspect-plan-golden` - `metro-billing-provider-preview-golden` - `metro-command-catalog` - `metro-command-reference-golden` - `metro-customer-setup-fixtures` - `metro-customer-setup-preview-golden` - `metro-docs-explain-billing-provider-attachment-golden` - `metro-docs-explain-ci-local-checks-golden` - `metro-docs-explain-customer-setup-golden` - `metro-docs-explain-first-safe-preview-golden` - `metro-docs-explain-input-normalize-golden` - `metro-docs-explain-install-troubleshooting-golden` - `metro-docs-explain-output-anatomy-golden` - `metro-docs-explain-package-publish-readiness-golden` - `metro-docs-explain-product-rate-retirement-readback-golden` - `metro-docs-explain-refusal-troubleshooting-golden` - `metro-docs-explain-setup-troubleshooting-golden` - `metro-docs-explain-topic-index-golden` - `metro-input-files` - `metro-input-normalize` - `metro-input-normalize-api-golden` - `metro-input-normalize-shape-golden` - `metro-input-reference` - `metro-input-reference-golden` - `metro-install-test` - `metro-package-test` - `metro-product-retirement-preview-golden` - `metro-release-artifact-manifest-golden` - `metro-release-evidence-check-golden` - `metro-release-evidence-plan-golden` - `metro-release-readiness-golden` - `metro-release-retention-policy-golden` - `metro-safe-preview-quickstart` - `metro-setup-fixtures` - `metro-setup-profiles` - `metro-setup-quickstart` - `metro-setup-resolve-golden` - `metro-workspace-routing` - `metronome-customers-hierarchies` - `metronome-stripe-delivery` - `packages-contracts` - `rate-cards-dimensional` - `shape-complimentary-credit-grant` - `shape-dimensional-rate-card` ## sources - `docs/SAFETY.md` - `docs/metronome-cli/CLI_ARCHITECTURE.md` - `docs/metronome-cli/COOKBOOK.md` - `docs/metronome-cli/GOTCHAS.md` - `docs/metronome-cli/QUICKSTART.md` - `docs/metronome-cli/README.md` - `docs/metronome-cli/SHAPE_CATALOG.md` - `docs/metronome-cli/SHAPE_CATALOG.md#product-or-rate-retirement` - `docs/metronome-cli/VALIDATION_AND_GUARDRAILS.md` - `docs/metronome-cli/VALIDATION_AND_GUARDRAILS.md#rate-card-rules` - `docs/metronome-cli/one-goal.md` - `docs/metronome-cli/site/agents.md` - `docs/metronome-cli/site/install.html` - `docs/metronome-cli/site/install.html#first-safe-preview` - `docs/metronome-cli/site/integration.html` - `docs/metronome-cli/site/verify-site.js` - `https://docs.metronome.com/api-reference/billable-metrics/create-a-billable-metric.md` - `https://docs.metronome.com/api-reference/contracts/get-the-rate-schedule-for-a-contract.md` - `https://docs.metronome.com/api-reference/customers/create-a-customer.md` - `https://docs.metronome.com/api-reference/customers/fetch-billing-provider-configurations-for-a-customer.md` - `https://docs.metronome.com/api-reference/customers/get-a-customer.md` - `https://docs.metronome.com/api-reference/customers/list-customers.md` - `https://docs.metronome.com/api-reference/customers/set-billing-provider-configurations-for-a-customer.md` - `https://docs.metronome.com/api-reference/customers/update-a-customer-configuration.md` - `https://docs.metronome.com/api-reference/invoices/list-invoices.md` - `https://docs.metronome.com/api-reference/products/archive-a-product.md` - `https://docs.metronome.com/api-reference/products/create-a-product.md` - `https://docs.metronome.com/api-reference/products/get-a-product.md` - `https://docs.metronome.com/api-reference/rate-cards/add-rates.md` - `https://docs.metronome.com/api-reference/rate-cards/get-a-rate-schedule.md` - `https://docs.metronome.com/api-reference/rate-cards/get-rates.md` - `https://docs.metronome.com/api-reference/settings/list-account-level-billing-providers.md` - `package.json` - `packages/metro-core/src/api-catalog/preview.js` - `packages/metro-core/src/api-catalog/read-pipeline.js` - `packages/metro-core/src/api-catalog/read-refusal.js` - `packages/metro-core/src/api-catalog/readiness.js` - `packages/metro-core/src/api-catalog/validation.js` - `packages/metro-core/src/apply-gate/index.js` - `packages/metro-core/src/audit/index.js` - `packages/metro-core/src/commands/catalog.js` - `packages/metro-core/src/docs/explain.js` - `packages/metro-core/src/docs/input-reference.js` - `packages/metro-core/src/input/files.js` - `packages/metro-core/src/input/normalize.js` - `packages/metro-core/src/inspect/index.js` - `packages/metro-core/src/preflight/index.js` - `packages/metro-core/src/preview/index.js` - `packages/metro-core/src/proof/sandbox-manifest.js` - `packages/metro-core/src/release/readiness.js` - `packages/metro-core/src/setup/profiles.js` - `packages/metro-core/src/shapes/index.js` - `packages/metro-core/src/validators/index.js` - `skills/metronome-customers-hierarchies/SKILL.md` - `skills/metronome-danger-zone/SKILL.md` - `skills/metronome-danger-zone/references/endpoint-matrix.md` - `skills/metronome-danger-zone/references/endpoint-matrix.md#11-invoices` - `skills/metronome-danger-zone/references/endpoint-matrix.md#15-settings--security` - `skills/metronome-danger-zone/references/endpoint-matrix.md#3-products` - `skills/metronome-danger-zone/references/endpoint-matrix.md#4-rate-cards` - `skills/metronome-danger-zone/references/endpoint-matrix.md#6-customers` - `skills/metronome-danger-zone/references/endpoint-matrix.md#7-billing-provider-configs-stripe` - `skills/metronome-danger-zone/references/endpoint-matrix.md#9-contracts` - `skills/metronome-packages-contracts/SKILL.md` - `skills/metronome-stripe-delivery/SKILL.md` ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. > Plus 14 source-document topics, one per Metronome docs page metro cites. List them with `metro docs explain --list`. --- # Gotchas > Known Metronome gotchas and the rules that cover them. Source: https://metrocli.com/docs/reference/gotchas/ · Docs index: https://metrocli.com/llms.txt Known Metronome traps, each mapped to the validator rule that covers it, or marked as a gap. > **Source.** Generated from `metro docs gotcha-reference --markdown` in metrocli/metro @146bf3e. Source schemaVersion: `metro.docs.gotcha-reference.v1`. - schemaVersion: `metro.docs.gotcha-reference.v1` ## Summary ```json { "gotchaCount": 59, "coveredCount": 58, "partialCount": 0, "openQuestionCount": 0, "coverageStatusCounts": { "covered": 58, "open": 1 }, "categoryCounts": { "Tenant And Authentication": 4, "Endpoint And Method Shape": 4, "Packages": 7, "Contracts": 4, "Billing Provider And Stripe": 4, "Customers": 6, "Subscriptions": 4, "Rate Cards And Products": 8, "Credits And Commits": 5, "Invoices": 4, "Usage Ingest": 3, "Bulk Workflows": 3, "Repo Hygiene": 3 } } ``` ## Gotchas | id | category | coverageStatus | gotcha | | --- | --- | --- | --- | | tenant-selected-by-key | Tenant And Authentication | covered | Production and sandbox share the same Metronome base URL; the API key selects the tenant. | | env-file-not-authorization | Tenant And Authentication | covered | A local .env file or existing key is not authorization. | | never-infer-production-from-key-presence | Tenant And Authentication | covered | Loading both production and sandbox keys is common; the CLI must never infer production from key presence. | | fingerprints-not-key-values | Tenant And Authentication | covered | Print key fingerprints, never key values. | | read-endpoints-can-be-post | Endpoint And Method Shape | covered | Many Metronome read endpoints are POST. | | get-endpoints-can-use-query-parameters | Endpoint And Method Shape | covered | Some list/get endpoints are GET with query parameters. | | verify-endpoint-before-implementation | Endpoint And Method Shape | covered | Before implementing any endpoint, verify it against the local endpoint matrix and current Metronome docs. | | do-not-guess-endpoint-paths | Endpoint And Method Shape | covered | Do not guess endpoint paths from names. | | package-contract-restricted-payload | Packages | covered | Package-based contract create accepts a restricted payload; extras such as commits or overrides belong in separate edit workflows. | | normalize-package-uniqueness-prefix | Packages | covered | Package uniqueness_key may be returned with a package: prefix; normalize before comparing. | | package-alias-resolution-at-starting-at | Packages | covered | Package alias resolution depends on the contract starting_at, not when the command runs. | | do-not-archive-old-package-before-alias-live | Packages | covered | Do not archive the old package version until the new alias is live and verified. | | package-plan-move-renewal-two-step | Packages | covered | Package plan moves should use updateEndDate, then create a successor with transition.type RENEWAL; package contracts do not support SUPERSEDE. | | move-plan-requires-open-ended-predecessor | Contracts | covered | metro contract move-plan preflight requires exactly one open-ended contract (no ending_before); active trials and expired customers do not qualify. | | expired-contract-rebuy-no-transition | Contracts | open | Expired contracts (ending_before in the past) must rebuy via fresh contracts/create without a transition block; do not pass RENEWAL from_contract_id on lapsed predecessors. | | renewal-transition-active-handoff-only | Contracts | covered | RENEWAL transitions are for active predecessor handoffs where successor starting_at aligns with predecessor ending_before; not for rebuy after lapse. | | free-trial-package-duration-expiry | Packages | covered | Package duration (DAYS) generates contract ending_before at provision; trial expiry is not a separate job. | | free-zero-rollover-on-rebuy | Contracts | covered | Free trials use rollover_fraction 0; RENEWAL on rebuy carries no useful credits - prefer fresh create when predecessor is expired. | | package-plan-move-billing-day-realignment | Packages | covered | Billing-day realignment with charge today uses package-plan-move-immediate-invoice: review paid-period overlap (refund vs no refund) before current-hour cutover. | | billable-workflow-requires-billing-provider | Billing Provider And Stripe | covered | Billable customer or contract workflows must prove billing provider config. | | stripe-delivery-behavior-explicit | Billing Provider And Stripe | covered | Stripe delivery behavior must be explicit: push to Stripe, keep draft, or no Stripe side effect expected. | | billing-provider-archive-replace-risk | Billing Provider And Stripe | covered | Archiving or replacing billing provider configs can affect invoice delivery. | | multi-entity-stripe-fields-not-guessed | Billing Provider And Stripe | covered | Multi-entity Stripe delivery needs endpoint-specific fields and should not be guessed. | | customer-lookup-is-get | Customers | covered | Customer lookup and search use GET paths with query parameters, not POST customer list payloads. | | customer-resolve-name-must-not-full-scan | Customers | covered | Name/external-id customer resolve must not paginate the entire /v1/customers list; stop at first exact hit and route email-shaped names through ingest_alias. | | customer-ingest-alias-collisions | Customers | covered | ingest_aliases are globally unique per tenant, and archived customers can keep aliases pinned. | | customer-set-ingest-aliases-replaces | Customers | covered | setIngestAliases replaces the full alias list; it is not additive. | | customer-hierarchy-lives-on-contracts | Customers | covered | Hierarchy is not a customer field; parent/child links live on contracts via hierarchy_configuration. | | customer-custom-field-whitelist | Customers | covered | Customer custom-field keys are allowlisted per entity type and values are limited to 200 characters. | | subscription-config-compatibility | Subscriptions | covered | Subscription invoicing requires compatible subscription configuration, not just a product and rate. | | subscription-billing-frequency-alignment | Subscriptions | covered | Billing frequency must align across rate-card setup and contract/subscription setup. | | subscription-rate-identity | Subscriptions | covered | Product ID and billing frequency together may identify the intended subscription rate. | | subscription-quantity-seat-source | Subscriptions | covered | Quantity or seat source must be explicit. | | product-archive-does-not-remove-rate-card-entry | Rate Cards And Products | covered | Product archive does not remove active rate-card entries. | | retirement-requires-entitled-false | Rate Cards And Products | covered | Retiring a product requires closing rate entries with entitled:false before archive. | | scheduled-product-update-readback | Rate Cards And Products | covered | Scheduled product updates may need the endpoint that exposes version history or schedule for verification. | | dimensional-metric-compound-group-key | Rate Cards And Products | covered | Dimensional action pricing must use one compound billable-metric group key for action_code and action_display_name. | | dimensional-one-product-not-per-action | Rate Cards And Products | covered | Dimensional action pricing should use one USAGE product with pricing_group_key, not one product per action. | | dimensional-scope-four-tier-cards | Rate Cards And Products | covered | Multi-tier dimensional rollout means four tier cards (payg, core, select, pro) - not every rate card in the tenant. | | dimensional-metro-route-first | Rate Cards And Products | covered | For new action codes, run metro route and metro docs explain rate-cards.dimensional, then metro dimensional new-code for production apply. | | starting-at-hour-boundary | Rate Cards And Products | covered | starting_at values must be hour-boundary timestamps. | | access-schedule-credit-type-is-access-credit | Credits And Commits | covered | access_schedule.credit_type_id is the product/access credit type for usage. | | invoice-schedule-fiat-credit-type | Credits And Commits | covered | invoice_schedule.credit_type_id must be a fiat currency when present. | | complimentary-grant-omit-invoice-schedule | Credits And Commits | covered | Complimentary grants should omit invoice_schedule unless a deliberate zero-dollar audit line is required. | | paid-topup-invoice-stripe-behavior | Credits And Commits | covered | Paid top-ups must state invoice and Stripe behavior before preview or apply. | | custom-field-keys-approved | Credits And Commits | covered | Custom-field keys must be approved for the target object type. | | past-dated-scheduled-charges-finalize | Invoices | covered | Past-dated scheduled charges can finalize immediately. | | metronome-void-does-not-refund-stripe | Invoices | covered | Voiding in Metronome does not refund Stripe. | | archive-with-voiding-reconciliation-gap | Invoices | covered | Archiving contracts or customers with invoice voiding can create reconciliation gaps. | | invoice-issue-date-stripe-behavior | Invoices | covered | Invoice issue-date changes must include expected Stripe behavior. | | historical-usage-finalized-period-risk | Usage Ingest | covered | Historical usage can alter finalized-period economics or create follow-up billing effects. | | usage-transaction-id-idempotency | Usage Ingest | covered | Transaction IDs must be stable for idempotency. | | bulk-ingest-canary-period-target | Usage Ingest | covered | Bulk ingest needs a canary and a clear invoice-period target. | | dry-run-not-metronome-write-proof | Bulk Workflows | covered | Dry-run does not prove every Metronome write validator will accept a payload. | | bulk-writes-need-manifest-canary-readback | Bulk Workflows | covered | Bulk writes need preview, manifest, canary, read-back verification, and resumable audit log. | | partial-failure-resume-evidence | Bulk Workflows | covered | A partial failure must not leave the next run guessing what already happened. | | do-not-promote-one-off-scripts | Repo Hygiene | covered | Do not promote old one-off scripts into CLI commands. | | do-not-depend-on-generated-artifacts | Repo Hygiene | covered | Do not depend on ignored generated artifacts as current source. | | external-billing-evidence-historical | Repo Hygiene | covered | Evidence from a previous billing system is historical unless a task explicitly asks for legacy migration context. | ## Agent notes - Prefer `--json` when scripting parsers; use `--markdown` when loading context into an agent. - Never treat HTML as the source of truth, regenerate from `metro docs --markdown`. - Live reads/writes still require tenant flags + confirmation tokens. --- # Changelog > Metronome upstream changes and metro coverage. Source: https://metrocli.com/docs/reference/changelog/ · Docs index: https://metrocli.com/llms.txt Metronome's upstream changes, and whether metro covers each one. Source: [docs.metronome.com/changelog](https://docs.metronome.com/changelog). > **Source.** Generated from `docs/metronome-cli/METRONOME_UPSTREAM_CHANGELOG.md` in metrocli/metro @146bf3e. Source schemaVersion: `n/a (hand-authored markdown)`. Source of truth: [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) Machine-readable markdown: [https://docs.metronome.com/changelog.md](https://docs.metronome.com/changelog.md) Docs index: [https://docs.metronome.com/llms.txt](https://docs.metronome.com/llms.txt) Last synced into metro: **2026-07-15** (`docs/metronome-cli/site/metronome-upstream.json`). Metro does **not** auto-ingest OpenAPI. This page is the checklist that keeps shapes, the endpoint matrix, and `api-catalog` honest when Metronome ships changes. ## How to refresh ```bash # Offline: does the frozen inventory still match expected key count? npm run docs:upstream:check # Explicit network: fetch changelog.md and report new/missing titles npm run docs:upstream:check -- --fetch ``` When `--fetch` reports new entries: curl every linked Metronome `.md` page, update `skills/metronome-danger-zone/references/endpoint-matrix.md` and/or `packages/metro-core/src/api-catalog/index.js` + shapes/validators, bump `syncedAt`, regenerate goldens/site if catalog output changed, and rewrite coverage notes in `scripts/generate-metronome-upstream.js` (or re-run it). ## Coverage legend | Status | Meaning | |---|---| | `accounted` | Metro catalog/skills/docs already cover the behavior | | `partial` | Related coverage exists; missing gotcha, shortcut, or validator prose | | `gap` | API-relevant and not yet represented - fix before relying on the feature | | `n/a` | Not an applicable metro operating surface | | `n/a-sdk` / `n/a-ui` | SDK or UI-only; no metro shape work unless API fields change | ## Gaps that need follow-up - **GAP** May 29, 2026 - Configurable rounding for prorated subscriptions and recurring commits: No shape/validator/docs yet for proration rounding fields. Curl subscription + recurring commit API docs before first use. - **GAP** February 5, 2026 - Get net balance API: Verified in endpoint-matrix (`POST /v1/contracts/customerBalances/getNetBalance`) but **not** yet a reviewed api-catalog ID / `metro api read` shape. Prefer over paginating balances when consolidating. - **Partial** July 7, 2026 - Daily recurring credits and commits are supported: Catalog/shapes cover recurring commits generally; daily cadence (`commit_duration` / recurrence unit daily) not yet called out in TEAM-QUICKSTART or shape prose. Re-curl create/edit docs before using daily. - **Partial** February 27, 2026 - Compound group keys in usage breakdowns: `usage.groups` is in api-catalog; compound group key constraint and page-size 100 not yet in validator prose/TEAM-QUICKSTART. - **Partial** February 17, 2026 - Change end date on advance, prorated subscriptions: Subscription end-date edits exist via contract/subscription edit paths; advance-prorated edge case not a dedicated gotcha yet. - **Partial** February 12, 2026 - Stripe invoice PDFs available in UI and API: Matrix notes invoice PDF GET path in conventions; not a first-class `metro` shortcut. Prefer Stripe dashboard or guarded invoice get when needed. - **Partial** February 10, 2026 - Subscription and invoice line item linking improvements: `subscription_id` on line items / Stripe metadata - useful for reconcile; not yet a metro proof field. - **Partial** January 16, 2026 - Major version SDK release: Breaking: removed `use_list_prices` from Rate objects - ensure rate-card payloads/validators do not emit it. - **Partial** October 14, 2025 - September fixes and improvements: Spot-check API subsection against edit/billing-provider sources when touching those shapes. - **Partial** September 10, 2025 - August fixes and improvements: Historical API fixes (billing config updates via edit, etc.) - reflected in danger-zone / stripe-delivery skills. - **Partial** August 5, 2025 - July fixes and improvements: API notes (searchEvents, commits) - events.search / commits paths in catalog. - **Partial** August 4, 2025 - Seat-based credit pools: Seat / credit pool shapes in skills; not a TEAM-QUICKSTART one-liner. - **Partial** July 23, 2025 - Threshold billing and auto-recharge: Spend/prepaid thresholds via contract edit - danger-zone aware; not a dedicated metro shortcut. - **Partial** June 26, 2025 - Scope credits and commits to specific pricing or presentation group values: Specifier / dimensional scoping; keep sources current. - **Partial** June 13, 2025 - Support for seat-based subscription billing: Seat subscriptions in skills; most packages are credit+plan fee shaped. - **Partial** May 20, 2025 - April fixes and improvements: Historical; verify touched endpoints against current `.md` sources. - **Partial** April 1, 2025 - Support for weekly frequencies for billing, recurring commits, and credits: Cadence fields exist; weekly not a common shape. - **Partial** March 26, 2025 - In Tempo: Spring 2025 changelog: Large release note - recurring commits, uniqueness keys, invoice breakdowns, updateEndDate guard already reflected across matrix/catalog/skills. - **Partial** September 25, 2024 - In Tempo: Fall 2024: voidInvoice etc. in catalog; plan-era APIs are historical. ## Batch / large requests (smart paths) Metronome guides: [high-volume ingestion](https://docs.metronome.com/guides/events/high-volume-ingestion), [send usage events](https://docs.metronome.com/guides/events/send-usage-events), [API quickstart](https://docs.metronome.com/guides/get-started/api-quickstart). | Need | Smart path in metro | Do not | |---|---|---| | Full package inventory | `metro package list --sandbox` or `--prod` (follows `next_page`) | Single-page `api read` and assume page = tenant | | Who is on a package | `metro package customers --package ` | Manual contracts-on-package loops without page follow | | Many plan moves | `metro contract move-plan bulk-preflight` then `bulk-apply` with `--delay-ms` / `--limit` canary | Parallel writers across the fleet | | New action code on all cards | `metro dimensional new-code --all ...` | Hand-rolled per-card scripts | | Usage aggregates (multi-customer) | Reviewed `usage.batch` + query `next_page` | Stuffing pagination into POST body | | Usage by dimensions | `usage.groups` (compound keys only if BM defines them; max page 100) | Grouping by multiple simple keys | | Combined credit+commit balance | Prefer **getNetBalance** once catalogued; until then balances list + pagination | N+1 per commit without a reason | | Ingest | Batches ≤100 events; stable transaction IDs; retry client on 429 | Firehose without backoff | | Rate append | `addRates` ≤100 rows per call | Mega payloads | | Audit log export | `metro audit export plan` documents pagination; live pull is gated | Unbounded concurrent page fetches | Pagination rule (current API): for nearly all modern list endpoints, `limit` and `next_page` belong in the **URL query string**, not the POST body. (Older local notes that said “send next_page in the body” are wrong for packages, getRates, usage.groups/batch, contracts-on-package, etc. - validators enforce query.) Retry: metro uses `metronome-retry-client` (429/5xx backoff). Still prefer serial pagination + bulk `--delay-ms` over high concurrency. ## Full inventory (every Metronome entry) ### July 7, 2026 - Daily recurring credits and commits are supported Tags: Billing, API, UI **Metro coverage:** `partial` - Catalog/shapes cover recurring commits generally; daily cadence (`commit_duration` / recurrence unit daily) not yet called out in TEAM-QUICKSTART or shape prose. Re-curl create/edit docs before using daily. Catalog IDs: `contracts.create`, `contracts.edit` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### May 29, 2026 - Configurable rounding for prorated subscriptions and recurring commits Tags: Billing, API, UI **Metro coverage:** `gap` - No shape/validator/docs yet for proration rounding fields. Curl subscription + recurring commit API docs before first use. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### May 29, 2026 - Richer responses from `createContract` and `editContract` Tags: API **Metro coverage:** `accounted` - Catalog sources point at create/edit docs. Metro still requires expected-vs-actual re-read after apply (richer response does not replace proof). Catalog IDs: `contracts.create`, `contracts.edit` Metronome links: - [Create contract API docs](https://docs.metronome.com/api-reference/contracts/create-a-contract#response-data) - [Edit contract API docs](https://docs.metronome.com/api-reference/contracts/edit-a-contract#response-data) ### May 15, 2026 - Metronome Java SDK is now available Tags: SDK **Metro coverage:** `n/a-sdk` - Metro is Node CLI; Java SDK not used. Metronome links: - [javadoc.io](https://javadoc.io/doc/com.metronome.api/metronome-java/latest/index.html) - [README](https://github.com/Metronome-Industries/metronome-java) ### April 17, 2026 - Q1 usability updates: quality of life improvements Tags: Improvements, UI **Metro coverage:** `n/a-ui` - UI-only QoL; no API shape impact. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### April 11, 2026 - Assign RBAC roles to API tokens Tags: New releases, UI **Metro coverage:** `accounted` - Token scope matters for operator mode + keys. Documented under platform RBAC link; prefer reader tokens with `metro mode set read-only`. Metronome links: - [here](https://docs.metronome.com/guides/platform-configuration/role-based-access-rbac#assign-a-role-to-an-api-token) ### April 11, 2026 - Package contract transitions and credit rollover improvements Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `accounted` - Package transitions and `rollover_fraction` used in preview/contract-move shapes and skills. Catalog IDs: `packages.create`, `contracts.create`, `contracts.edit` Metronome links: - [provisioning customers with a package](https://docs.metronome.com/guides/get-started/core-concepts/packages-overview#provision-customers-with-a-package) - [contract lifecycle transitions](https://docs.metronome.com/guides/customers-billing/manage-customers/manage-customer-lifecycle) - [credits and rollovers](https://docs.metronome.com/guides/pricing-packaging/apply-credits-and-commits/create-a-pre-paid-commit) ### April 11, 2026 - NetSuite integration (Public Beta) Tags: New releases, Integrations **Metro coverage:** `n/a` - Invoices via Stripe, not NetSuite. Metronome links: - [here](https://docs.metronome.com/integrations/invoice-integrations/netsuite) ### March 9, 2026 - Dark mode Tags: New releases, UI **Metro coverage:** `n/a-ui` - UI only. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### March 2, 2026 - SDK releases Tags: New releases, API **Metro coverage:** `n/a-sdk` - Track only when release notes imply API schema breakers (e.g. removed `priority`). Metro catalog is hand-curated. Metronome links: - [Go v3.2.0](https://github.com/Metronome-Industries/metronome-go/compare/v3.1.0...v3.2.0) - [Python v4.2.0](https://github.com/Metronome-Industries/metronome-python/compare/v4.1.0...v4.2.0) - [Ruby v3.2.0](https://github.com/Metronome-Industries/metronome-ruby/compare/v3.1.0...v3.2.0) - [Node v3.2.0](https://github.com/Metronome-Industries/metronome-node/compare/v3.1.0...v3.2.0) ### February 27, 2026 - Compound group keys in usage breakdowns Tags: New releases, API **Metro coverage:** `partial` - `usage.groups` is in api-catalog; compound group key constraint and page-size 100 not yet in validator prose/TEAM-QUICKSTART. Catalog IDs: `usage.groups` Metronome links: - [Get usage data with paginated groupings](https://docs.metronome.com/api-reference/usage/get-usage-data-with-paginated-groupings) - [here](https://docs.metronome.com/api-reference/usage/get-usage-data-with-paginated-groupings) ### February 23, 2026 - Archive packages Tags: New releases, API, UI **Metro coverage:** `accounted` - `packages.archive` in api-catalog + validators. Catalog IDs: `packages.archive` Metronome links: - [API](https://docs.metronome.com/api-reference/packages/archive-a-package) ### February 19, 2026 - New Metronome UI Tags: New releases, UI **Metro coverage:** `n/a-ui` - UI only. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 17, 2026 - Change end date on advance, prorated subscriptions Tags: New releases, API **Metro coverage:** `partial` - Subscription end-date edits exist via contract/subscription edit paths; advance-prorated edge case not a dedicated gotcha yet. Catalog IDs: `contracts.edit` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 12, 2026 - Stripe invoice PDFs available in UI and API Tags: New releases, API, UI **Metro coverage:** `partial` - Matrix notes invoice PDF GET path in conventions; not a first-class `metro` shortcut. Prefer Stripe dashboard or guarded invoice get when needed. Catalog IDs: `invoices.get` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 10, 2026 - Subscription and invoice line item linking improvements Tags: Improvements, API, Integrations **Metro coverage:** `partial` - `subscription_id` on line items / Stripe metadata - useful for reconcile; not yet a metro proof field. Catalog IDs: `invoices.get`, `invoices.listForCustomer` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 9, 2026 - Create contracts from packages in the UI Tags: New releases, UI **Metro coverage:** `n/a-ui` - API path already covered (`packages` + `contracts.create`). UI convenience only. Catalog IDs: `contracts.create` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 6, 2026 - In-app embedded dashboards Tags: New releases, UI **Metro coverage:** `n/a-ui` - UI reporting; use metro + exports. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### February 5, 2026 - SDK releases Tags: New releases, API **Metro coverage:** `n/a-sdk` - Track only when release notes imply API schema breakers (e.g. removed `priority`). Metro catalog is hand-curated. Metronome links: - [Go v3.1.0](https://github.com/Metronome-Industries/metronome-node/compare/v3.0.0...v3.1.0) - [Python v4.1.0](https://github.com/Metronome-Industries/metronome-python/compare/v4.0.0...v4.1.0) - [Ruby v3.1.0](https://github.com/Metronome-Industries/metronome-ruby/compare/v3.0.0...v3.1.0) - [Node v3.1.0](https://github.com/Metronome-Industries/metronome-node/compare/v3.0.0...v3.1.0) ### February 5, 2026 - Get net balance API Tags: New releases, API **Metro coverage:** `gap` - Verified in endpoint-matrix (`POST /v1/contracts/customerBalances/getNetBalance`) but **not** yet a reviewed api-catalog ID / `metro api read` shape. Prefer over paginating balances when consolidating. Metronome links: - [Get net balance](https://docs.metronome.com/api-reference/credits-and-commits/get-the-net-balance-of-a-customer) - [here](https://docs.metronome.com/api-reference/credits-and-commits/get-the-net-balance-of-a-customer) ### January 29, 2026 - Edit net payment terms on contracts Tags: New releases, API, UI **Metro coverage:** `accounted` - Preview supports `net_payment_terms_days`; edit history still required for audit. Catalog IDs: `contracts.edit` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### January 16, 2026 - Major version SDK release Tags: New releases, API **Metro coverage:** `partial` - Breaking: removed `use_list_prices` from Rate objects - ensure rate-card payloads/validators do not emit it. Catalog IDs: `rateCards.addRates`, `rateCards.getRates` Metronome links: - [Node v3.0.0](https://github.com/Metronome-Industries/metronome-node/releases) - [Go v3.0.0](https://github.com/Metronome-Industries/metronome-go/releases) - [Python v4.0.0](https://github.com/Metronome-Industries/metronome-python/releases) - [Ruby v3.0.0](https://github.com/Metronome-Industries/metronome-ruby/releases) ### January 12, 2026 - Self-serve access to Metronome Tags: New releases, UI **Metro coverage:** `n/a-ui` - Onboarding UI. Metronome links: - [Metronome website](https://metronome.com) ### January 12, 2026 - Billing configuration API endpoints now return response bodies Tags: Improvements, API **Metro coverage:** `accounted` - Billing-provider set/archive in catalog; responses expected in sandbox-proof paths. Catalog IDs: `customers.setBillingProviderConfigurations`, `customers.archiveBillingProviderConfigurations` Metronome links: - [set billing provider configuration](https://docs.metronome.com/api-reference/customers/set-billing-provider-configurations-for-a-customer) - [archive billing provider configuration](https://docs.metronome.com/api-reference/customers/archive-billing-provider-configurations-for-a-customer) ### December 22, 2025 - High cardinality group key spend alerts Tags: New releases, Notifications **Metro coverage:** `n/a` - Alerts not in metro core day-to-day. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### December 19, 2025 - SDK releases Tags: New releases, API **Metro coverage:** `n/a-sdk` - Track only when release notes imply API schema breakers (e.g. removed `priority`). Metro catalog is hand-curated. Metronome links: - [Node v2.2.0](https://github.com/Metronome-Industries/metronome-node/releases) - [Go v2.2.0](https://github.com/Metronome-Industries/metronome-go/releases) - [Python v3.2.0](https://github.com/Metronome-Industries/metronome-python/releases) - [Ruby v2.2.0](https://github.com/Metronome-Industries/metronome-ruby/releases) ### November 14, 2025 - Launch week recap: Monetization Infrastructure for AI Tags: New releases, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `n/a-ui` - Marketing recap; follow linked product guides when relevant. Metronome links: - [here](https://docs.metronome.com/guides/pricing-packaging/billing-model-guides/hybrid-business-models#use-case) - [here](https://docs.metronome.com/guides/pricing-packaging/subscription/subscription-overview) - [here](https://docs.metronome.com/guides/get-started/core-concepts/packages-overview) - [here](https://metronome.com/blog/monetize-ai-with-full-pricing-flexibility) - [here](https://docs.metronome.com/guides/invoices/invoice-with-metronome#invoice-with-metronome) - [here](https://docs.metronome.com/integrations/marketplace-integrations/gcp) - [here](https://metronome.com/blog/unify-invoicing-across-every-revenue-motion) - [here](https://docs.metronome.com/guides/customers-billing/optimize-customer-experience/preview-event-cost) - [here](https://docs.metronome.com/guides/invoices/invoice-with-metronome#metronome-billing-console) - [here](https://docs.metronome.com/guides/customers-billing/set-up-notifications/create-and-manage-notifications#manage-your-customer-lifecycle-with-metronome-notifications) - [here](https://metronome.com/blog/make-billing-part-of-the-product-experience) - [metronome.com/launch-week](http://metronome.com/launch-week) ### November 3, 2025 - Invoicing with Google Cloud Marketplace Tags: New releases, Integrations **Metro coverage:** `n/a` - Uses Stripe billing. Metronome links: - [here](https://docs.metronome.com/integrations/marketplace-integrations/gcp#invoice-with-gcp) ### October 31, 2025 - New SDK releases Tags: New releases, API **Metro coverage:** `n/a-sdk` - Track only when release notes imply API schema breakers (e.g. removed `priority`). Metro catalog is hand-curated. Metronome links: - [v2.1.0](https://github.com/Metronome-Industries/metronome-node/releases) - [v2.1.0](https://github.com/Metronome-Industries/metronome-go/releases) - [v3.1.0](https://github.com/Metronome-Industries/metronome-python/releases) - [v2.1.0](https://github.com/Metronome-Industries/metronome-ruby/releases) ### October 14, 2025 - September fixes and improvements Tags: Improvements, API, Notifications, UI, Pricing and Packaging **Metro coverage:** `partial` - Spot-check API subsection against edit/billing-provider sources when touching those shapes. Catalog IDs: `contracts.edit` Metronome links: - [`spend_threshold_reached`](https://docs.metronome.com/guides/customers-billing/optimize-customer-experience/customer-controls#enable-custom-spend-limits-for-a-specific-dimension%E2%80%8B) - [Add a billing configuration](https://docs.metronome.com/api-reference/contracts/edit-a-contract#body-add-billing-provider-configuration-update) - [Archive a billing provider](https://docs.metronome.com/api-reference/customers/archive-billing-provider-configurations-for-a-customer) - [Edit the rate type of a recurring commit](https://docs.metronome.com/api-reference/credits-and-commits/edit-a-commit#body-rate-type) - [Node](https://github.com/Metronome-Industries/metronome-node/releases/tag/v1.0.0) - [Go](https://github.com/Metronome-Industries/metronome-go/releases/tag/v1.0.0) - [Python](https://github.com/Metronome-Industries/metronome-python/releases/tag/v1.0.0) - [Ruby](https://github.com/Metronome-Industries/metronome-ruby/releases/tag/v1.0.0) ### September 24, 2025 - Make advanced contract overrides in the Metronome app Tags: New releases, UI, Pricing and Packaging **Metro coverage:** `n/a-ui` - UI for overrides; API overrides remain via `contracts.edit`. Catalog IDs: `contracts.edit` Metronome links: - [here](https://docs.metronome.com/guides/pricing-packaging/make-pricing-changes/edit-or-override-a-contract#contract-edits-and-overrides) ### September 24, 2025 - Custom Reports Tags: New releases, UI **Metro coverage:** `n/a-ui` - In-app reports. Metronome links: - [here](https://docs.metronome.com/guides/reporting-insights/in-app-reporting#custom-reports) ### September 18, 2025 - Customer Lifecycle Notifications Tags: New releases, API, Notifications, UI **Metro coverage:** `n/a` - Notifications not operated via metro today. Metronome links: - [here](https://docs.metronome.com/guides/customers-billing/set-up-notifications/create-and-manage-notifications) ### September 11, 2025 - New documentation experience Tags: New releases, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `accounted` - Sources use docs.metronome.com `.md` URLs + llms.txt. This tracker is the metro-side sync surface. _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### September 10, 2025 - August fixes and improvements Tags: Improvements, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Historical API fixes (billing config updates via edit, etc.) - reflected in danger-zone / stripe-delivery skills. Catalog IDs: `contracts.edit` Metronome links: - [data exports](https://docs.metronome.com/developer-resources/data-export) - [edit a commit](https://docs.metronome.com/api/#operation/editCommit-v2) - [products](https://docs.metronome.com/api/#operation/createProduct-v1) - [create contract](https://docs.metronome.com/api/#operation/createContract-v1) - [get an invoice](https://docs.metronome.com/api/#operation/getInvoice-v1) - [list invoice breakdowns](https://docs.metronome.com/api/#operation/listBreakdownInvoices-v1) - [list invoices](https://docs.metronome.com/api/#operation/listInvoices-v1) - [Node](https://github.com/Metronome-Industries/metronome-node/releases/tag/v0.1.0) - [Go](https://github.com/Metronome-Industries/metronome-go/releases) - [Python](https://github.com/Metronome-Industries/metronome-python/releases) - [Ruby](https://github.com/Metronome-Industries/metronome-ruby/releases) - [edit contract](https://docs.metronome.com/api/#operation/editContract-v2) ### August 15, 2025 - Invoice breakdowns in Data Export Tags: New releases, UI **Metro coverage:** `partial` - `invoices.listBreakdowns` in catalog; data-export tables are separate. Catalog IDs: `invoices.listBreakdowns` Metronome links: - [here](https://docs.metronome.com/guides/reporting-insights/data-export#invoice-breakdowns-tables) ### August 5, 2025 - July fixes and improvements Tags: Improvements, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `partial` - API notes (searchEvents, commits) - events.search / commits paths in catalog. Catalog IDs: `events.search`, `commits.list` Metronome links: - [prepaid](https://docs.metronome.com/pricing-packaging/apply-credits-commits/#prepaid-commits) - [postpaid](https://docs.metronome.com/pricing-packaging/apply-credits-commits/#postpaid-commits) - [Search events](https://docs.metronome.com/api/#operation/searchEvents-v1) - [`/v1/contracts/customerCommits/create`](https://docs.metronome.com/api/#operation/createCustomerCommit-v1) - [`/v2/contracts/edit`](https://docs.metronome.com/api/#operation/editContract-v2) - [`/v1/contracts/create`](https://docs.metronome.com/api/#operation/createContract-v1) - [`v2/contracts/edit`](https://docs.metronome.com/api/#operation/editContract-v2) - [`v2/contracts/get`](https://docs.metronome.com/api/#operation/getContract-v2) - [`v1/contracts/customerCommits/list`](https://docs.metronome.com/api/#operation/listCustomerCommits-v1) - [`v2/contracts/list`](https://docs.metronome.com/api/#operation/listContracts-v2) - [Node](https://github.com/Metronome-Industries/metronome-node/releases/tag/v0.1.0) - [Go](https://github.com/Metronome-Industries/metronome-go/releases) - [Python](https://github.com/Metronome-Industries/metronome-python/releases) - [Ruby](https://github.com/Metronome-Industries/metronome-ruby/releases) - [Send Metronome events to Slack](https://docs.metronome.com/developer-resources/use-api/webhooks/#send-webhooks-to-slack) ### August 4, 2025 - Use group keys to set budgets across users, teams, and projects Tags: New releases, API, Notifications, UI **Metro coverage:** `n/a` - Spend controls/alerts - not metro day-to-day. Metronome links: - [group key values](https://docs.metronome.com/connect-metronome/create-billable-metrics/#group-keys) - [here](https://docs.metronome.com/launch-guides/hybrid-business/) - [here](https://docs.metronome.com/enhance-customer-experience/customer-controls/#enable-custom-spend-limits-for-a-specific-dimension) ### August 4, 2025 - Seat-based credit pools Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Seat / credit pool shapes in skills; not a TEAM-QUICKSTART one-liner. Catalog IDs: `contracts.edit` Metronome links: - [here](https://docs.metronome.com/enhance-customer-experience/customer-controls/#enable-custom-spend-limits-for-a-specific-dimension) - [See docs here.](https://docs.metronome.com/launch-guides/hybrid-business/) ### August 1, 2025 - Embeddable dashboard for credit and commit balances Tags: New releases, API **Metro coverage:** `n/a-ui` - Embeddable UI; metro uses balances list / (future) getNetBalance. Catalog IDs: `customerBalances.list` Metronome links: - [here](https://docs.metronome.com/enhance-customer-experience/customer-dashboards/#commits-and-credits-dashboard) ### July 23, 2025 - Threshold billing and auto-recharge Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Spend/prepaid thresholds via contract edit - danger-zone aware; not a dedicated metro shortcut. Catalog IDs: `contracts.edit` Metronome links: - [here](https://docs.metronome.com/pricing-packaging/apply-credits-commits/manual-payment-gated-commits/) - [here](https://docs.metronome.com/manage-product-access/spend-thresholds#create-a-contract-with-spend-thresholds) - [here](https://docs.metronome.com/manage-product-access/prepaid-balance-thresholds/) - [here](https://docs.metronome.com/launch-guides/prepaid-credits/) - [here](https://metronome.com/blog/choosing-the-right-plg-billing-models-for-your-business) ### July 15, 2025 - Set up multi-entity billing Tags: New releases, Integrations **Metro coverage:** `partial` - Account hierarchy / billing config - skills note hierarchy; careful with Stripe entity. Catalog IDs: `customers.setBillingProviderConfigurations` Metronome links: - [here](https://docs.metronome.com/invoice-customers/solutions/invoice-with-stripe/#set-the-customer-billing-configuration) ### June 26, 2025 - Scope credits and commits to specific pricing or presentation group values Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Specifier / dimensional scoping; keep sources current. Catalog IDs: `contracts.edit`, `rateCards.addRates` Metronome links: - [here](https://docs.metronome.com/pricing-packaging/apply-credits-commits/target-credits-commits/) ### June 13, 2025 - Edit recurring commits and credits Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `accounted` - Recurring edit via contracts.edit / commit edit docs in skills. Catalog IDs: `contracts.edit` Metronome links: - [here](https://docs.metronome.com/api/#operation/editContract-v2) ### June 13, 2025 - Support for seat-based subscription billing Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Seat subscriptions in skills; most packages are credit+plan fee shaped. Catalog IDs: `contracts.create`, `contracts.edit` Metronome links: - [here](https://docs.metronome.com/manage-product-access/create-subscription/#update-pricing) - [here](https://docs.metronome.com/manage-product-access/create-subscription/) ### May 20, 2025 - April fixes and improvements Tags: Improvements, API, Integrations, UI **Metro coverage:** `partial` - Historical; verify touched endpoints against current `.md` sources. Metronome links: - [`getCustomer`](https://docs.metronome.com/api/#operation/getCustomer-v1) - [`listCustomers`](https://docs.metronome.com/api/#operation/listCustomers-v1) - [`getInvoice`](https://docs.metronome.com/api/#operation/getInvoice-v1) - [`listInvoices`](https://docs.metronome.com/api/#operation/listInvoices-v1) - [`listBreakdownInvoices`](https://docs.metronome.com/api/#operation/listBreakdownInvoices-v1) - [here](https://docs.metronome.com/api/#operation/archiveRateCard-v1) ### May 8, 2025 - Remove overrides and archive commits and scheduled charges Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `accounted` - editContract archive/remove paths documented in danger-zone. Catalog IDs: `contracts.edit` Metronome links: - [here](https://docs.metronome.com/api/#operation/editContract-v2) ### May 5, 2025 - Support for NZD and SGD currencies Tags: New releases, Pricing and Packaging **Metro coverage:** `n/a` - Standard currency amounts. Metronome links: - [here](https://docs.metronome.com/pricing-packaging/use-currency-custompricingunits/) ### May 1, 2025 - Ruby SDK Tags: New releases, API **Metro coverage:** `n/a-sdk` - SDK only. Metronome links: - [here](https://github.com/Metronome-Industries/metronome-ruby) - [here](https://docs.metronome.com/developer-resources/sdks/) ### April 29, 2025 - Updated UI for creating and editing contracts, customer-level commits, and customer-level credits Tags: New releases, UI **Metro coverage:** `n/a-ui` - UI only. Metronome links: - [available through the API](https://docs.metronome.com/api/#operation/editContract-v2) ### April 9, 2025 - Edit rates in the Rate Card UI Tags: Improvements, UI **Metro coverage:** `n/a-ui` - API: addRates/getRates in catalog. Catalog IDs: `rateCards.addRates` _No deep links in the changelog body - start from [https://docs.metronome.com/changelog](https://docs.metronome.com/changelog) and curl the matching API/guide page via [llms.txt](https://docs.metronome.com/llms.txt)._ ### April 2, 2025 - Usage threshold alerts supported on Contracts Tags: New releases, API, Notifications **Metro coverage:** `n/a` - Alerts out of metro day-to-day. Metronome links: - [here](https://docs.metronome.com/manage-product-access/create-manage-alerts/#usage-alerts) ### April 2, 2025 - Contract editing Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `accounted` - `contracts.edit` + danger-zone editContract support matrix. Catalog IDs: `contracts.edit` Metronome links: - [Read more in our docs.](https://docs.metronome.com/manage-product-access/edit-contract/) ### April 1, 2025 - Support for weekly frequencies for billing, recurring commits, and credits Tags: New releases, API, UI, Pricing and Packaging **Metro coverage:** `partial` - Cadence fields exist; weekly not a common shape. Catalog IDs: `contracts.create`, `contracts.edit` Metronome links: - [docs](https://docs.metronome.com/api/#operation/createContract-v1) ### March 26, 2025 - In Tempo: Spring 2025 changelog Tags: New releases, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `partial` - Large release note - recurring commits, uniqueness keys, invoice breakdowns, updateEndDate guard already reflected across matrix/catalog/skills. Catalog IDs: `contracts.create`, `contracts.edit`, `contracts.updateEndDate`, `invoices.listBreakdowns`, `customerBalances.list` Metronome links: - [here](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - [here](https://docs.metronome.com/manage-product-access/create-manage-alerts/#create-an-alert) - [here](https://docs.metronome.com/api/#operation/listBreakdownInvoices) - [here](https://docs.metronome.com/enhance-customer-experience/customer-dashboards/#display-up-to-date-spend) - [here](https://docs.metronome.com/api/#operation/listCustomerBalances) - [here](https://docs.metronome.com/api/#operation/createCustomerCommit) - [here](https://docs.metronome.com/api/#operation/listRateCards) - [here](https://docs.metronome.com/api/#operation/updateContractEndDate) - [request body](https://docs.metronome.com/api/#operation/updateContractEndDate) - [API](https://docs.metronome.com/api/#operation/createContract) - [here](https://docs.metronome.com/pricing-packaging/apply-credits-commits/#provision-recurring-usage-credits) - [here](https://docs.metronome.com/pricing-packaging/apply-credits-commits/discounts/) - [here](https://metronome.com/blog/say-goodbye-to-overages-hello-to-commit-rates) - [here](https://docs.metronome.com/launch-guides/quickstart#create-composite-products) - [Metronome Trust Center](https://trust.metronome.com/) - [here](https://docs.metronome.com/invoice-customers/solutions/invoice-with-stripe/#configure-optional-global-integration-settings-available) - [here](https://docs.metronome.com/developer-resources/data-export/#contracts_commits) - [we launched Metronome 2.0](https://metronome.com/blog/introducing-metronome-2-0) - [here](https://docs.metronome.com/invoice-customers/solutions/marketplaces/) - [here](https://docs.metronome.com/pricing-packaging/use-currency-custompricingunits#supported-currencies) - [here](https://docs.metronome.com/api/#operation/embeddableDashboard) - [here](https://metronome.com/talk-to-an-expert?utm_medium=web\&utm_source=blog\&utm_campaign=intempo_spring_2024) ### October 17, 2024 - Metronome 2.0 Tags: New releases, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `accounted` - Metro is built on Metronome 2.0 contracts/rate-cards/packages model. Metronome links: - [managing rate cards](https://docs.metronome.com/pricing-packaging/create-manage-rate-cards/) - [customizing pricing](https://docs.metronome.com/manage-product-access/provision-customer/#add-contract-discounts-and-overrides) - [enterprise commit launch guide](https://docs.metronome.com/launch-guides/enterprise-commit/) - [dimensional pricing](https://docs.metronome.com/pricing-packaging/create-manage-rate-cards/#dimensional-pricing) - [billable metrics](https://docs.metronome.com/connect-metronome/create-billable-metrics/) - [customer and contract provisioning](https://docs.metronome.com/manage-product-access/provision-customer/) - [building customer dashboards](https://docs.metronome.com/enhance-customer-experience/customer-dashboards/) - [API documentation](https://docs.metronome.com/api) - [customer spend controls](https://docs.metronome.com/enhance-customer-experience/customer-controls/) - [creating and managing alerts](https://docs.metronome.com/manage-product-access/create-manage-alerts/) - [syncing billing data into Salesforce](https://docs.metronome.com/reports-insights/sync-into-salesforce/) ### September 25, 2024 - In Tempo: Fall 2024 Tags: New releases, API, Notifications, UI, Pricing and Packaging **Metro coverage:** `partial` - voidInvoice etc. in catalog; plan-era APIs are historical. Catalog IDs: `invoices.void` Metronome links: - [here](https://docs.metronome.com/api/#operation/voidInvoice) - [Go](https://pkg.go.dev/github.com/Metronome-Industries/metronome-go#section-readme) - [Python](https://pypi.org/project/metronome-sdk/) - [TypeScript](https://www.npmjs.com/package/@metronome/sdk) - [here](https://docs.metronome.com/connecting-metronome/alerts/#usage-threshold-reached) - [here](https://docs.metronome.com/connecting-metronome/alerts#invoice-total-reached) - [here](https://docs.metronome.com/invoicing/how-billing-works/set-up-seat-based-billing/#how-seat-based-billing-works) - [here](https://docs.metronome.com/pricing-and-packaging/create-plans/#fixed-fee-and-tiered-usage) - [here](https://docs.metronome.com/api/#operation/createGrant) - [here](https://docs.metronome.com/developer-resources/export-metronome-data/#customer_plan) - [here](https://metronome.com/talk-to-an-expert?utm_medium=web\&utm_source=blog\&utm_campaign=intempo_fall_2024) ### June 10, 2024 - In Tempo: Spring 2024 Tags: New releases, API, Notifications, Integrations, UI, Pricing and Packaging **Metro coverage:** `n/a-ui` - Mostly pre-2.0/plan-era; do not copy paths into new workflows without matrix check. Metronome links: - [here](https://docs.metronome.com/api/#billable-metrics) - [here](https://docs.metronome.com/api/#operation/createAlert) - [here](https://docs.metronome.com/connecting-metronome/alerts/#forcing-alert-re-evaluation) - [here](https://docs.metronome.com/api/#operation/resetCustomerAlerts) - [here](https://docs.metronome.com/api/#operation/addPlanToCustomer) - [here](https://docs.metronome.com/api/#operation/createGrant) - [AWS Marketplace integration](https://docs.metronome.com/invoicing/how-invoicing-works/invoicing-with-aws-marketplace/) - [here](https://docs.metronome.com/api/#operation/getAuditLogs) - [here](https://docs.metronome.com/integrations/workato-connector/)