Invoices
Update an invoice issue date, with the Stripe expectations reviewed first.
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.
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.
{
"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."
}metro validate --shape invoice-issue-date-update --file issue-date.json
metro invoice issue-date preview --file issue-date.json --sandbox✓ 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: nostripeBehavior 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.
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 --jsonCompare 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 |