Who can use this: Organization Owners (and Solavel staff via the admin shell). Managers and Members cannot reach billing. URL / Route:
/portal/orgs/{organization}/billing/*,/portal/orgs/{organization}/plan*,/admin/subscriptions/*Plan / feature gate: Always on (the prices and limits depend on the plans configured by Solavel staff)
Purpose
This page covers everything money-related: choosing or changing a plan, paying with a card via Tap, viewing invoices, downloading receipts, replacing a card, and canceling. Billing is centralized — even Solabooks subscriptions are paid here, not inside Solabooks.
How a subscription is structured
- An organization has at most one active subscription at a time.
- A subscription is linked to a project plan — for example, "Solabooks / Premium" — and a billing cycle (monthly).
- The card-charging step is handled by the Tap payment gateway. After Tap finishes, it redirects back to
portal.orgs.billing.tap.return, and the receipt-side webhook arrives atPOST /api/webhooks/tap.
Behind the scenes the table is client_subscriptions(client_id, project_plan_id, status, starts_at, billing_cycle_starts_at, billing_cycle_ends_at). The active project plans are seeded from database/seeders/ProjectPlanSeeder.php.
Step by step
Pick or upgrade a plan
- From the sidebar, open Billing → Subscriptions (
portal.orgs.billing.subscriptions.index). - Click Change plan (or Upgrade). You arrive at
portal.orgs.plan.show. - Pick a tier. The form posts to
portal.orgs.plan.update. If the tier costs more than the current one, you go through Tap to authorize the new card charge. If it is free or already paid for, the change applies immediately.
Cancel at the end of the period
- Open Billing → Subscriptions.
- Click Cancel at period end (
POST portal.orgs.billing.subscription.cancel_at_period_end). Access continues untilbilling_cycle_ends_at, then the subscription becomes inactive. - To undo a pending cancellation, click Resume (
POST portal.orgs.billing.subscription.resume) before the period ends.
There is also an immediate-cancel route at portal.orgs.plan.cancel. It ends access right away — use only when the user explicitly asks for it.
Replace or remove a card
- List cards:
portal.orgs.billing.payment_methods.index. - Replace the default:
POST portal.orgs.billing.payment_methods.replace. Tap captures the new card. - Set default:
POST portal.orgs.billing.payment_methods.{paymentMethod}.default. - Remove a card:
DELETE portal.orgs.billing.payment_methods.{paymentMethod}.destroy. You cannot remove the only card on file while a subscription is active.
View invoices and payments
- Invoices list:
portal.orgs.billing.invoices.index. - Invoice detail / download PDF:
portal.orgs.billing.invoices.show. - Payments list:
portal.orgs.billing.payments.index.
Pay an outstanding invoice
If a card charge fails, the invoice goes to pending and the subscription marks past_due. Use Billing → Overview (portal.orgs.billing.show) to see the prompt and click Pay now, which calls POST portal.orgs.billing.tap.initiate to start a new Tap charge.
Tap payment flow
Every card charge follows the same shape:
POST portal.orgs.billing.tap.initiate— Solavel asks Tap for a redirect URL.- The user is sent to Tap's hosted checkout.
- Tap calls
GET portal.orgs.billing.tap.returnafter the user completes (or cancels) the form. - Asynchronously, Tap calls the webhook at
POST /api/webhooks/tap. Solavel verifies the signature inside the controller, marks the invoice paid, and activates the subscription.
The same flow is used for the new-organization wizard at portal.orgs.create.checkout.
Risk:
POST /api/webhooks/tapis reachable without auth — only Tap's signature check protects it. Do not expose the webhook URL outside of Tap's own dashboard.
Plan upgrade flow during onboarding
When a new organization is being created, the plan choice happens inside the Create organization wizard (see Organizations). Free plans skip the checkout step. Paid plans go through Tap and return to portal.orgs.create.checkout.return, which finishes activation.
Admin-side subscription tools
For Solavel staff:
/admin/subscriptions(admin.subscriptions.index) — searchable list of every subscription./admin/subscriptions/{subscription}(admin.subscriptions.show) — detail view with status timeline and links into the related client and organization.
Direct subscription mutations (cancel, reactivate) for staff use the client.subscriptions.* API:
GET /subscriptions(client.subscriptions.index)POST /subscriptions/{subscription}/cancel(client.subscriptions.cancel)POST /subscriptions/{subscription}/reactivate(client.subscriptions.reactivate)
These are used from inside the admin shell — they are not advertised in the sidebar.
Note: an older
/admin/subscriptions/sync-logsroute was removed in November 2025; the sidebar entry was dropped in commit 60d5d85.
Permissions / restrictions
- See billing pages: requires
manage-subscriptionspermission. Held by Owners and by Solavel staff. Managers and Members do not see the Billing menu. - Cancel at period end / resume: requires
manage-subscriptions. - Replace card: requires
manage-subscriptions. - View invoices: requires
manage-subscriptionsorview-client-subscription. - Admin-side subscription read:
view-client-subscription. Admin-side cancel/edit:edit-client-subscription.
Common problems
- "Your card was declined." — Tap shows the reason in its return page. Try a different card from
portal.orgs.billing.payment_methods.index. - The subscription says
past_due— the renewal charge failed. Pay the open invoice fromportal.orgs.billing.show. - After Tap return, you are still on a free plan. The webhook has not yet fired or has failed. Check
admin.system-event-logs.indexfor the Tap webhook entry. The page auto-refreshes once the webhook arrives. - Cannot cancel because there is an outstanding invoice. Pay the invoice first, or contact Solavel support.