Self-service seat changes: account-area "change seats" → Paddle subscription update #12
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Today there is no customer-facing path to grow a license from 55 to 65 seats. The account area's only commerce affordance is the buy flow, which starts a new checkout → new subscription → a second full-price license, while the old subscription keeps billing — and seats don't stack across keys in cairnd, so this is a trap. The only correct route is editing the subscription quantity in the Paddle seller dashboard by hand.
The underlying machinery is already right: a quantity change on the existing subscription produces a prorated
transaction.completedon the samesubscription_id, the webhook's refresh branch re-signs the same license id with the new seat count, and the instance auto-installs the refreshed key at its next check-in (Cairn#58). Only the trigger is missing.Plan:
POST /v1/licenses/{id}/seats{seats}(Bearer; org-admin; license must belong to the caller's org and be subscription-backed). Reads the subscription from Paddle, PATCHes its item quantity withproration_billing_mode: "prorated_immediately", returns 202 — the webhook then updates the license asynchronously. Extends the existingpaddleAPIclient with a write method.PADDLE_API_KEYon the VPS was deliberately created read-only (receipts). Subscription writes need Read+Write on Subscriptions — Nikola updates the key in the Paddle sandbox dashboard and on the VPS.Depends on the origin fix (#11) landing first, so an upgrade transaction doesn't wrongly extend expiry.
Shipped and deployed (PRs #13, #14, cairn-site #3; license server restarted healthy, site pushed). Remaining before this actually works end-to-end — both Nikola's:
PADDLE_API_KEYin/etc/cairn-license/envon the VPS,sudo systemctl restart cairn-license-server. The signing key and everything else stay untouched.license refreshed, the license row shows the new seat count with an unchanged expiry, and aPOST /v1/checkinreturns the re-signed key.Until (1) is done the endpoint answers 502 with a "billing provider rejected" message and logs the scope hint — nothing breaks, the button is just inert.