Skip to content

Billing

OPanel’s built-in billing uses Stripe Checkout for signup and the Stripe Customer Portal for self-service billing. Card data never touches your servers, which keeps you in PCI SAQ-A scope. If you already bill through another system, skip Stripe entirely and drive subscriptions through the API instead.

For each plan you sell, create a Stripe Product with one or more recurring Prices (monthly, yearly, or both). Then, in Admin → Plans, add a matching price to the plan with the Stripe price ID (price_...), the interval and the amount, which should match what you set in Stripe.

Under Admin → Billing (or PATCH /api/v1/billing/settings):

Field Notes
Provider stripe
Secret key A restricted key (rk_...) or secret key (sk_...). Use sk_test_... until you’ve verified the whole flow.
Public URL The https:// origin customers use, e.g. https://panel.example.com — Stripe redirects here after checkout and from the portal
Grace period Days a past-due subscription keeps serving before suspension (default 7)

Keys are encrypted with the installation’s master key before they’re stored.

In Stripe → Developers → Webhooks, add an endpoint pointing at https://<panel host>/api/v1/billing/stripe/webhook (the Billing settings page shows the exact URL), subscribed to:

checkout.session.completed
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
customer.subscription.paused
customer.subscription.resumed
invoice.paid
invoice.payment_failed

Copy the endpoint’s signing secret (whsec_...) into the Billing settings. Webhook events are stored before processing and applied exactly once, so Stripe’s retries are harmless.

Stripe event What happens
checkout.session.completed Customer created, buyer becomes its owner, subscription created, first site created if a domain was entered at signup
invoice.payment_failed Subscription goes past due; sites keep serving through the grace period
Grace period elapses Subscription is suspended: sites show a suspended page, SSH is denied, data is kept
invoice.paid Past-due or suspended subscriptions become active again
customer.subscription.deleted Subscription is cancelled, scheduled for termination
Retention period elapses Subscription is terminated and its sites deleted (files and database dumps kept in trash for the node’s own retention window)

Every Stripe event is treated as a notification, not a command: the controller re-reads the subscription’s live state from Stripe and applies that, so late, duplicate or out-of-order webhook deliveries can never move a subscription backwards. A subscription suspended by staff, or for non-payment, stays that way until staff or payment resolve it — Stripe events alone never lift it.

External billing: WHMCS, Blesta and HostBill

Section titled “External billing: WHMCS, Blesta and HostBill”

If you already run one of these, keep it: OPanel provides billing modules for WHMCS, Blesta and HostBill, and a provisioning API for any other system. Subscriptions created this way carry billingProvider: external; OPanel does not attempt to charge them, and the external system drives every lifecycle transition — activation, suspension, cancellation — through the same API endpoints staff use.

Point your billing system’s OPanel module at your panel’s API base URL and an API token scoped to customer:manage, billing:manage and site:create; the module handles provisioning a customer, subscription and site on order, and suspending or terminating on non-payment, the same way the built-in Stripe integration does.

Deleting a customer (DELETE /api/v1/customers/{id}) closes the account rather than erasing it — sites, subscriptions and the audit log all refer to it. It’s refused while any subscription is active, trialing or past due; cancel those first. A closed customer keeps read access to what remains and can be reopened (POST /api/v1/customers/{id}/reopen), which does not revive subscriptions that already finished terminating.

Reseller brands with their own Stripe account

Section titled “Reseller brands with their own Stripe account”

A brand can bill through the platform’s Stripe account, or through an account of its own — see Brands.