Contracts
Contracts from packages or direct, transitions, overrides and end dates.
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 · Edit a contract · Update the contract end date · Archive a contract · 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.
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,MULTIPLIERorTIERED. 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.
RENEWALhands off to a successor and carries overbalance × rollover_fraction. On package contracts, the verified pattern is two steps: end the old contract, then create the successor withRENEWAL.SUPERSEDEreturns400on package contracts.
Gotchas
- A contract edit is atomic: if one operation fails, nothing applies. Some edits return
200and silently don't apply, so always read back. - A contract that was renewed or superseded and has finalized invoices can't be edited.
updateEndDatedefaultsallow_ending_before_finalized_invoicetotrue. Shortening a contract truncates draft statements and removes upcoming scheduled invoices.- Archiving a contract requires
void_invoices.truevoids 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=<hour> --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=<alias> | End the current contract, then a RENEWAL successor. Needs one active contract to move from. |
metro contract extend-trial preflight --extend-by-days=<N> | 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 <id> --sandbox --plan | A read plan for one contract |
See Create a contract and Move a customer. Metronome docs: Create a contract.