billing_hub
No security coverage
Billing Hub
Gateway-agnostic billing layer for Drupal 10 / 11. Manages subscriptions,
invoices, tax, and dunning. Integrates with Membership Manager for access
control. Supports Stripe, PayPal, Braintree, and custom payment gateways via a Plugin API.
Requirements
- Drupal 10.2+ or Drupal 11
- PHP 8.2+
drupal:user(core)membership_managermodule
Gateway dependencies
# Stripe composer require stripe/stripe-php # PayPal composer require paypal/paypal-server-sdk
Installation
composer require drupal/billing_hub drush en billing_hub billing_hub_stripe drush cr
Visit /admin/billing to configure.
Architecture Overview
CheckoutService → BillingManagerService → GatewayPlugin BillingPortalController → BillingManagerService → SubscriptionService WebhookController → WebhookDispatcherService → BillingManagerService DunningService → Queue → DunningQueueWorker → GatewayPlugin::retryInvoice() TaxService ← BillingPlan + TaxRate AnalyticsService ← billing_subscription + billing_invoice tables
BillingManagerService is the central entry point.
Billing Plans
Field Description Machine name Used in code Gateway Gateway plugin Price Base price Currency ISO 4217 Interval day / week / month / year Interval count Billing frequency Trial days Trial duration Proration Enable credits Dunning policy cancel / downgrade / suspend Tax mode exclusive / inclusive / none Membership plan Linked membershipGateway Configuration
Field Description Plugin ID stripe / paypal / braintree Test mode Sandbox mode Settings API keysStripe example
secret_key: sk_live_... publishable_key: pk_live_... webhook_secret: whsec_... test_mode: false
Checkout Flow
PHP Example
$checkout = \Drupal::service('billing_hub.checkout'); $preview = $checkout->preview( plan_id: 'pro_monthly', country_code: 'DE', tax_id: 'DE123456789' ); $result = $checkout->checkout( user: $user, plan_id: 'pro_monthly' );
AJAX Preview
fetch('/billing/checkout/pro_monthly/preview', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ country_code: 'DE' }) });
Subscription Lifecycle
active → canceled active → paused → active active → past_due → unpaid trialing → active
Webhooks
Gateway URL Stripe /billing/webhook/stripe PayPal /billing/webhook/paypal Braintree /billing/webhook/braintreeDunning
Retry schedule: 0, 1, 3, 7, 14 days
Policy Effect cancel Subscription canceled downgrade Assign fallback plan suspend Keep recordTax
Modes
Mode Description exclusive Tax added inclusive Tax included none No taxVAT validation hook
function mymodule_billing_hub_vat_validate(string $vat_number): bool { return my_vies_client()->validate($vat_number); }
Analytics
$analytics = \Drupal::service('billing_hub.analytics'); $analytics->getMRR(); $analytics->getARR(); $analytics->getChurnRate(30);
User Billing Portal
Route Description /billing/portal Overview /billing/portal/invoices Invoices /billing/portal/cancel/{id} Cancel /billing/portal/change-plan/{id} Change planMembership Integration
BillingPlan.membership_plan_id → assignMembership() → MembershipManagerService::assign()
Custom Gateway
/** * @Gateway( * id = "my_gateway", * label = @Translation("My Gateway") * ) */ class MyGateway extends GatewayPluginBase {}
Hooks
Coupon
function mymodule_billing_hub_coupon_validate(string $code): float { return 10.0; }
Redirect
function mymodule_billing_hub_checkout_success_url(...) { return '/members/welcome'; }
Maintainers
Dmytro Porokhnya
License
GPL-2.0-or-later