Author: Fywolf Requires: Pelican Panel · Filament v4 · PHP 8.2+
A production-ready billing plugin for game hosting panels. Handles the full lifecycle of server orders — from checkout to automatic monthly renewals — entirely through Stripe Subscriptions.
- Checkout uses Stripe Subscription mode — users are charged automatically every billing cycle
- No manual renewals required; Stripe handles the recurring charges
- Webhook-driven lifecycle:
checkout.session.completed→ activates the order and provisions the serverinvoice.paid→ extends subscription, unsuspends server if in grace periodinvoice.payment_failed→ moves order to grace periodcustomer.subscription.deleted→ expires the order and suspends the server
- Stripe Customers are created automatically and reused across orders
- Cancelling a subscription in the panel immediately cancels it in Stripe
- Create products with server specs: CPU, RAM, disk, swap, I/O weight
- Multiple price tiers per product (e.g. monthly, quarterly, yearly)
- Prices are synced as recurring Stripe Prices automatically; one-time prices are detected and recreated
- Products grouped by category (e.g. Minecraft, VPS) with configurable sort order
- Per-price environment variable overrides for server startup configuration
- My Servers section at the top — shows all active servers as cards linking to the server console
- Products listed below, grouped by category with a heading per category
- Each product card shows CPU, RAM, disk, optional limits, and one order button per price tier
- Coupon code input on each product card (applied at Stripe checkout)
- Free tier products activate instantly with no payment
- Trial support: first-time trial orders skip payment for a configurable number of days
| Status | Description |
|---|---|
| Pending | Checkout session open, payment not yet received |
| Active | Subscription active, server running |
| Grace Period | Payment failed or expired — server stays online during grace window |
| Expired | Grace period exhausted — server suspended, subscription cancelled |
| Closed | Cancelled by user or admin |
- Automated expiry check every 5 minutes via
p:billing:check-orders - Configurable grace period (0–168 hours) before suspension on failed renewal
- Stale pending orders (>2 hours old) are automatically closed and Stripe sessions expired
- Servers created automatically after payment via a queued job with retry logic (3 attempts)
- Supports specific node targeting or auto-deployment via node tags
- Port range filtering for allocation selection
- On plan upgrade/downgrade, server startup variables are updated immediately
- Servers unsuspended on renewal/reactivation, suspended on expiry/cancellation
- Admin creates coupons with fixed or percentage discounts
- Coupons synced to Stripe and applied at checkout via Stripe's
discounts[]parameter - Coupon expiry dates and usage limits supported
- Customers enter coupon codes on the store — validated before checkout begins
- Dedicated order confirmation page after successful checkout
- URL uses a unique 64-character token that expires after 24 hours (not guessable)
- Confirmation email sent automatically with PDF invoice attached
- Order confirmation email sent after activation (queued for background delivery)
- PDF invoice attachment includes: order reference, product, price, expiry date, company info
- PDF generation via
barryvdh/laravel-dompdf— gracefully skipped if not installed
- Every significant event is recorded with context:
order_activated,order_renewed,order_expired,order_closedorder_grace_period_started,order_plan_upgrade,order_plan_downgradeserver_created,stripe_webhook_payment_received,stripe_subscription_renewedstripe_invoice_payment_failed,stripe_subscription_deleted- Admin-triggered actions:
admin_order_activated,admin_order_closed,admin_order_plan_changed
- Full audit log viewable per order in the admin panel
- Products — CRUD with category, sort order, server specs, deployment config (nodes, ports, tags)
- Prices — CRUD per product: interval, cost, trial days, environment overrides; auto-synced to Stripe
- Coupons — CRUD with type, value, expiry; auto-synced to Stripe
- Orders — Full table with status filters, gateway badge, customer/server links; actions: activate, change plan, cancel subscription, force-create server
- Customers — List with order history relation manager
- Audit Logs — Searchable log of all billing events
- Settings — Stripe credentials, webhook secret, currency, grace period, company info for invoices
- Store dashboard: My Servers → Products grouped by category
- Orders list with: status, server name, product, cost, expiry
- Per-order actions: open server console, change plan, pay pending order, cancel subscription
| Requirement | Version |
|---|---|
| Pelican Panel | Latest |
| PHP | 8.2+ |
| stripe/stripe-php | ^18.0 |
| barryvdh/laravel-dompdf | ^3.0 (optional — for PDF invoices) |
- Place the
billingfolder in your Pelican plugins directory - Install dependencies:
composer require stripe/stripe-php:"^18.0" barryvdh/laravel-dompdf:"^3.0"
- Run the database migrations:
php artisan migrate
- Go to Admin → Settings → Billing and enter your Stripe credentials
- In the Stripe Dashboard → Developers → Webhooks, create a webhook endpoint:
Enable these events:
https://your-panel.com/webhooks/stripecheckout.session.completed invoice.paid invoice.payment_failed customer.subscription.deleted - Copy the webhook signing secret (
whsec_…) into the Billing settings
| Setting | Description |
|---|---|
| Currency | USD, EUR, GBP, CAD, AUD |
| Grace Period (hours) | How long a server stays online after a failed renewal. 0 = suspend immediately |
| Default Node Tags | Tags used for auto-deployment when no specific nodes are selected on a product |
| Company Name / Address / Email / VAT / Website | Shown on PDF invoices |
| Stripe Publishable Key | pk_live_… |
| Stripe Secret Key | sk_live_… |
| Stripe Webhook Signing Secret | whsec_… |
| Migration | Description |
|---|---|
001_create_coupons_table |
Coupons with Stripe coupon sync |
002_create_customers_table |
Customer profiles linked to panel users |
003_create_products_table |
Products with server specs |
004_create_product_prices_table |
Pricing tiers per product |
005_create_orders_table |
Orders with payment and status tracking |
006_create_billing_audit_logs_table |
Audit log entries |
007_add_coupon_id_to_orders_table |
Coupon foreign key on orders |
008_add_confirmation_token_to_orders_table |
Expiring one-time confirmation tokens |
009_add_category_to_products_table |
Category and sort_order on products |
010_add_stripe_subscription_support |
stripe_subscription_id on orders, stripe_customer_id on customers |
One command is registered and runs automatically every 5 minutes:
php artisan p:billing:check-orders
This command:
- Moves Active orders past their
expires_atinto Grace Period (or directly to Expired if grace = 0) - Moves Grace Period orders whose window has elapsed to Expired, cancels the Stripe subscription, and suspends the server
- Closes stale Pending orders older than 2 hours
MIT — made by Fywolf