plan
Inspect subscription lifecycle and prices, preview a change, and manage billing with owner-only CLI writes.
solwyn plan
solwyn --json plan
solwyn plan list
solwyn --json plan listBare plan preserves solwyn.plan.v1, showing current tier, subscription status,
renewal/cancellation and grace timestamps, pending/scheduled changes, limits and
capabilities. plan list reads the authenticated billing catalog with
solwyn.plan.catalog.v1: monthly/yearly prices in integer cents, yearly monthly
display cents, currency/tax metadata, included requests, published overage rate,
string decimal cent metered price, limits and capabilities. Null prices/overage
remain null. No currency conversion or floating-point money conversion occurs.
The status payload preserves these lifecycle fields:
| Field | Meaning |
|---|---|
current_period_end | Renewal/term end; the end of the paid year on annual plans. |
cancel_at | Scheduled cancellation time, or null. The removed cancel_at_period_end boolean is not used. |
grace_period_until | Grace deadline, when supplied; displayed for past-due state. |
pending_plan | Paid-signup intent with tier/interval; not an active subscription. |
scheduled_plan_change | Nullable target tier/interval and effective_at; unknown target fields stay null. |
Limits and capabilities cover project/key quotas, budget modes/periods, thresholds, enforcement/ingest rates, failover and retention. A -1 limit renders as unlimited. Price/currency metadata comes from the catalog rather than a local price list.
Both reads accept JWT or project keys with the required account/user context;
Core enforces access. No project selection is required. Group/subcommand help
performs no API read. MCP offers plan_status and plan_catalog in both profiles.
# Any account JWT can read this estimate; no confirmation or billing effect.
solwyn --json plan change --tier team --interval year --dry-run
# Owner JWT required for every write below. Review effects before using --yes.
solwyn plan change --tier team --interval year
solwyn plan change --discard
solwyn plan cancel
solwyn plan resume
solwyn plan upgrade --tier production --interval month --no-browser
solwyn plan portal --no-browser
solwyn plan pending dismissEvery billing write, including checkout and portal session creation, displays its
effects and requires interactive confirmation or --yes. Without an interactive
terminal and without --yes, the command exits 2 before HTTP. Declining or EOF
also exits 2 without submitting a write. Core alone enforces billing.manage,
currently owner-only: admin/member JWTs cannot write. Billing commands require
JWT; an environment or stored project key masks login and must be unselected.
These commands have no MCP writer equivalents.
plan cancel ends the plan at the current plan term end: the current paid
year on annual plans, the month on monthly plans. There is no proration or refund;
the plan stays in effect until the returned cancel_at. plan resume clears a
cancellation made in Solwyn or the Stripe portal and resumes renewal at the same
term end. Both commands show lifecycle state first, then return Core's status
and required nullable cancel_at (solwyn.plan.cancel.v1 / solwyn.plan.resume.v1).
A null value remains null; the CLI never invents a cancellation date.
plan change --tier T --interval month|year fetches and displays the real Stripe
estimate before confirmation. production, team and scale are paid targets.
Core decides whether a change applies immediately with proration (an upgrade
that does not move year-to-month, including month-to-year tier upgrades, or
same-tier month-to-year) or waits until the current
term end (downgrades and every year-to-month switch, including upgrades).
The result preserves mode, effective_at, integer amount_due_cents and
total_cents, currency, and each line's description, signed cent amount, period
bounds and proration flag. Negative cents are credits. Scheduled previews say
nothing is due now. The estimate is not a price lock: timing and amounts can
drift before confirmation. The final request sends only target tier and interval;
it never submits the preview's proration_date.
The solwyn.plan.change.v1 envelope contains dry_run, preview, and result.
--dry-run performs only the preview POST, requires no confirmation, and leaves
result=null. A successful write includes Core's actual mode/status and optional
nullable proration date/effective date in result. JSON stdout contains one
result; effects, prompts, and browser notices go to stderr.
Preview requires an existing paid subscription. A free account or an account without a subscription receives billing_subscription_not_found (exit 5); use plan upgrade to create a checkout session instead.
plan change --discard displays the captured scheduled change before removing it.
It cannot combine with --tier, --interval, or --dry-run; invalid combinations
exit 2 before HTTP. Core's empty 204 establishes the desired discarded state,
whether or not a schedule existed; solwyn.plan.discard.v1 reports
discarded=true. A billing_plan_change_scheduled cancellation conflict points
here. billing_cancel_pending points to inspection and plan resume; payment
failure points to inspection and plan portal. Hints never perform recovery.
plan upgrade creates a hosted checkout session; plan portal creates a hosted
billing-management session. Neither response proves payment or a subscription
change occurred. Core may expire older open checkout sessions when creating a new one. Both always print their returned HTTPS URL
(solwyn.plan.upgrade.v1.checkout_url / solwyn.plan.portal.v1.portal_url) and
open it only in an interactive terminal unless --no-browser is set. Non-TTY
scripts never open a browser, even with --yes. Malformed URLs, credential-bearing
URLs, unsafe schemes and control characters are rejected before browser use.
A browser failure preserves the successfully created URL and advises opening it
manually. Checkout generates one request ID retained across eligible rejection
retries; a later CLI invocation creates a new ID. Existing subscribers use
plan change, as the billing_subscription_active hint explains.
plan pending dismiss shows and removes the captured paid-signup intent; it does
not cancel or change an active subscription. A confirmed empty 204 means the
desired dismissal, not proof of a previous row. The
solwyn.plan.pending.dismiss.v1 result is dismissed=true; bare plan retains
its existing pending-plan visibility.
No billing POST/DELETE automatically replays a 503 or transport failure. For a
write, an unsuccessful response can leave its outcome unknown: inspect plan
and hosted billing state before deliberately retrying. A preview remains a read
and can be retried explicitly. Definite 401/429 rejection handling follows the
shared bounded client policy; checkout keeps the same request identity. Numeric
exit codes are unchanged: 0 success, 1 API/invalid response, 2 usage/confirmation,
3 authentication/role refusal and 5 not found. Applicable 409 details preserve
the typed optional status; private or unexpected billing detail fields fail
closed.
MCP plan_preview(tier, interval) is the same read-only estimate in both
profiles, with solwyn.plan.preview.v1. Like CLI dry-run it requires JWT at any
account role and no project selection; Core does not apply the owner write gate.
It retains the common deadline, response/result limits and safe error policy.