emeroid/laravel-billing-core
Driver-based, multi-gateway billing for Laravel with a fluent API for one-time payments and subscriptions. Supports Paystack and PayPal, plan swapping, grace-period cancellation, dunning via webhooks, events, and a Billable trait for your User model.
Install & Publish Config
composer require emeroid/laravel-billing-core
php artisan vendor:publish --provider="Emeroid\Billing\BillingServiceProvider" --tag="billing-config"
php artisan vendor:publish --provider="Emeroid\Billing\BillingServiceProvider" --tag="billing-migrations"
php artisan migrate
config/billing.php with your gateway (Paystack/PayPal) credentials.Add Billable Trait to User Model
use Emeroid\Billing\Traits\Billable;
class User extends Authenticatable
{
use Billable;
}
First Use Case: One-Time Payment
use Emeroid\Billing\Facades\Billing;
$user = auth()->user();
$payment = Billing::charge($user, 1000, 'USD', [
'description' => 'Premium Feature Unlock'
]);
Subscription Management
// Subscribe a user to a plan
$subscription = Billing::subscribe($user, 'monthly', [
'price' => 2999, // $29.99
'currency' => 'USD',
'trial_days' => 7
]);
// Cancel subscription (immediately or at end of period)
$subscription->cancel(); // Immediate
$subscription->cancel(true); // Cancel at end of period
// Swap plans (e.g., upgrade/downgrade)
$subscription->swapPlan('annual', [
'price' => 24999, // $249.99
'currency' => 'USD'
]);
Webhook Handling (Dunning)
invoice.payment_failed events:
public function handleWebhook(Request $request)
{
$event = Billing::handleWebhook($request);
if ($event->type === 'invoice.payment_failed') {
$subscription = $event->subscription;
$subscription->markPastDue();
}
}
Event Listeners
// app/Providers/EventServiceProvider.php
protected $listen = [
'Emeroid\Billing\Events\SubscriptionStarted' => [
'App\Listeners\SendWelcomeEmail',
],
'Emeroid\Billing\Events\SubscriptionCancelled' => [
'App\Listeners\NotifyUserCancellation',
],
];
plans table and reference them by ID in subscriptions.cancelAtEndOfPeriod for smoother user experience.BILLING_GATEWAY in .env (e.g., paystack → paypal).Webhook Verification
Billing::verifyWebhook() method.$isValid = Billing::verifyWebhook($request, $request->header('stripe-signature'));
Currency and Price Handling
$29.99 → 2999.Subscription State Confusion
cancelled vs. past_due: Use markPastDue() for failed payments (dunning) and cancel() for intentional cancellations.$subscription->status (e.g., active, cancelled, past_due).Migration Order
php artisan migrate
config/billing.php to log webhook payloads:
'debug' => env('BILLING_DEBUG', false),
BILLING_ENV=sandbox in .env).Custom Gateways
Emeroid\Billing\Contracts\Gateway interface to add support for Stripe, Flutterwave, etc.class StripeGateway implements Gateway
{
public function charge(...)
{
// Custom Stripe logic
}
}
config/billing.php under gateways.Custom Events
event(new CustomSubscriptionEvent($subscription));
Plan Validation
plan.validating event:
Billing::extend('plan.validating', function ($plan) {
if ($plan->price < 100) {
throw new \InvalidArgumentException('Price too low!');
}
});
How can I help you explore Laravel packages today?