~/docs/macos-app/subscription
╭─ § 04.05 ─╮

Subscription

└───────────╯

The Subscription room is the in-app home for everything billing-related: activating a license, seeing what’s unlocked, retrying validation when the network is flaky, managing your device, and opening the customer portal. It lives at the bottom of the sidebar under Manage (look for the star icon).

If you’re a free user, this page is also where Pro features are pitched and where you paste a license key after purchasing.

Accessing the Subscription Room

Open the main window (menu bar → Open Corral… or ⌘O), then select Subscription from the sidebar under Manage. The room renders one of three top-level layouts based on (daemon connected?, license info?):

  • Daemon not running — a hero with a single “Start Corral” button.
  • No active license — the Free layout (sales hero + feature grid + pricing tile).
  • Active license — the Pro layout (status hero + license panel + deactivate row).

The page re-renders automatically when the daemon publishes a LicenseCheck unit event — grace-period transitions, validation retries, and renewals all push into the UI without any explicit refresh.

Free Layout

When no license is active, the Subscription room shows:

  • Hero — Corral mark, the Corral version, and a single sales line.
  • What you get — a grid of the six Pro features (the in-app cards are static education; click a heading below to open its docs page):
    • Cloudflare data inspection — browse D1, KV, R2, Durable Objects, Workflows, and the Secrets Store — and, in the app, delete entries, edit TTLs, and reset local data.
    • Managed dev services — PostgreSQL, MariaDB, Valkey, Mailpit, OpenSearch, Meilisearch, MinIO, Typesense as native binaries.
    • System-wide terminal shimsnode, npm, npx shims installed into ~/.corral/bin/ so the right version follows you across every terminal.
    • Universal package managercorral pm and the cpm shim dispatch the right command for npm / yarn / pnpm / bun.
    • Browser & Network — capture HTTP requests, browser console, and page network activity in a searchable, persistent Network tab.
    • Stacks — compose projects and services into one runnable stack; start, stop, and restart the whole environment in dependency order (Cloudflare Workers auto-group).
  • Pricing tile — single-SKU, $49/year. Click Upgrade to Pro to open the checkout page on corral.sh/pro.
  • “I have a license key” — opens the activation sheet (see below).

Activating a License

Click “I have a license key” in the Free layout to open the activation sheet.

  1. Paste the key from your post-purchase email — it looks like CORRAL-XXXX-XXXX-XXXX-XXXX.
  2. Click Activate.
  3. On success, the sheet auto-dismisses and the Subscription room re-renders as Pro on the next runloop tick.

If activation fails, an inline error renders under the text field:

  • License key not recognised — the key was rejected by the licensing server. Double-check the key in your email; copy-paste rather than re-typing.
  • Activation limit reached — every seat is consumed. Deactivate the key on another device (in that device’s Subscription room) and try again.
  • Daemon / network errors — the licensing server was unreachable. Try again in a moment.

The error copy comes verbatim from the daemon’s typed FfiLicenseError variants, so the wording you see is the daemon’s source of truth.

Pro Layout

When a license is active, the room shows the Pro hero, the license panel, and the deactivate row.

Hero States

The hero has a colored status pip and a short headline. Six states cover everything the LicenseCheck unit’s lifecycle can express:

StatePipHeadlinePrimary CTAs
ActiveGreen (pulsing)Active · all features unlockedManage subscription
Grace (graceRemainingDays set)AmberValidating · grace expires in N day(s)Retry validation · Manage subscription
Grace expired (status: active, valid: false)RedValidation failed · Pro features lockedRetry validation · Manage subscription
Expired (status: expired)RedPlan expired dateRenew · Manage subscription
Disabled (status: disabled or inactive)RedPlan disabled · contact supportEmail support · Manage subscription
Daemon not runningGrayCorral isn’t runningStart Corral

License Panel

Below the hero, the license panel lists:

RowContent
CustomerName and email from the purchase
ProductThe product name (e.g., Corral Pro)
PlanYearly (or Lifetime when expires_at is null)
DevicesActivations used vs. limit (today: 1 / 1 — multi-seat is marked Coming Soon)
Renews / ExpiresThe date the next charge or expiry lands (or Lifetime)
License keyMasked by default (CORRAL-•••• ••••...) with Reveal and Copy affordances

All dates are rendered in UTC, not your local timezone. The licensing server emits UTC calendar dates (2026-11-04T00:00:00Z), and rendering through Calendar.current would silently shift them by a day for users in non-UTC zones. The Subscription room pins formatting to UTC so the displayed date always matches the value the server holds.

Retry Validation

Click Retry validation to dispatch a retry_unit against the LicenseCheck unit. This re-runs the daemon’s license check immediately rather than waiting for the next 24-hour tick.

When it helps:

  • The grace pip is amber because the network was down during the last validation.
  • You’re using a flaky connection (coffee shop wifi, tethered hotspot).
  • You just renewed in the customer portal and want the app to pick up the new expiry now.

When it doesn’t help:

  • The plan is genuinely expired or disabled — only renewing in the customer portal will fix that.

Manage Subscription

The Manage subscription button opens the customer portal in your default browser. The URL comes from the active license’s manage_url field — it’s a session link from the licensing provider, so no extra login is required. The portal is where you update billing, cancel, or download invoices.

Deactivating Your Device

Click Deactivate license in the deactivate row. A confirmation dialog appears.

  1. Confirm — the daemon tells the licensing server to release this device’s seat.
  2. On success — the license is removed from this device and the room re-renders as Free. The seat is freed for another machine.
  3. On network failure — a retry dialog appears with a typed { code, message, retry_after_secs } envelope. If you can’t reach the server, click Remove Locally to drop the license file on this device — useful when a seat is consumed but the server is unreachable so you’re not stranded. The seat will release on this device, but the server still considers the seat consumed until the next 24-hour revalidation reconciles.

If you change your mind, you can re-activate the same key on this device at any time.

Daemon-Down State

If the daemon isn’t running when you open the Subscription room (rare — the app auto-starts it on launch), you’ll see the gray-pip “Corral isn’t running” hero with a single Start Corral button.

Clicking the button re-runs the standard daemon-connect path with the same 3s / 6s / 9s retry budget used at launch. The button shows a spinner labeled Starting… while a connection attempt is in flight, and the call is idempotent — clicking twice doesn’t multiply attempts.

If the daemon won’t start after the full retry budget, check the Console app for daemon logs at ~/.corral/logs/.

How Pro Entitlement Is Decided

The macOS app derives isPro from the LicenseCheck unit’s lifecycle, not from the persisted license file’s valid boolean:

  • LicenseCheck is Active::ReadyPro
  • LicenseCheck is Active::Ready with grace remaining ⇒ Pro
  • Anything else (Pending, Idle, Failed) ⇒ Free

This mirrors the daemon’s own require_pro() gate (which gates D1/KV/R2/DO/Workflows/Secrets inspection, the exec resolver, managed services, and stack run/compose). Both sides read the same source of truth, so the UI’s Pro gates can never unlock ahead of the daemon. If a Pro feature looks locked when you think it shouldn’t, the Subscription room is where you’ll see the discrepancy — its hero is the canonical view of your entitlement state.

For where Pro gates render in the UI, see the bindings region on the project Overview tab (whole-region blur with a single centered upgrade pill when Free).

Support

For activation, billing, or pro-disabled questions, email [email protected].

// Last updated 2026-07-11