Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Stripe Subscription Bundle Laravel Package

advancingu/stripe-subscription-bundle

Laravel bundle for managing Stripe subscriptions and billing flows. Provides helpers for plans, customers, trials, cancellations, and webhook handling, aiming to simplify common subscription tasks and integrate Stripe into your app with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle via Composer:

    composer require advancingu/stripe-subscription-bundle
    

    Register the bundle in config/bundles.php:

    return [
        // ...
        Advancingu\StripeSubscriptionBundle\StripeSubscriptionBundle::class => ['all' => true],
    ];
    
  2. Configuration Publish the default config:

    php artisan vendor:publish --provider="Advancingu\StripeSubscriptionBundle\StripeSubscriptionBundle" --tag="config"
    

    Update .env with your Stripe keys:

    STRIPE_SECRET_KEY=your_secret_key
    STRIPE_WEBHOOK_SECRET=your_webhook_secret
    
  3. First Use Case: Create a Subscription Use the SubscriptionService in a controller:

    use Advancingu\StripeSubscriptionBundle\Service\SubscriptionService;
    
    public function createSubscription(Request $request, SubscriptionService $subscriptionService)
    {
        $customer = $subscriptionService->createCustomer($request->input('email'), $request->input('payment_method'));
        $subscription = $subscriptionService->createSubscription($customer->id, 'price_id_here');
    
        return response()->json($subscription);
    }
    
  4. Webhook Setup Add the webhook route in routes/web.php:

    Route::post('/stripe/webhook', [StripeWebhookController::class, 'handleWebhook']);
    

    Ensure the StripeWebhookController is implemented (see Implementation Patterns).


Implementation Patterns

Core Workflows

  1. Customer Management

    • Create/Update Customers:
      $customer = $subscriptionService->createCustomer($email, $paymentMethodId);
      $customer = $subscriptionService->updateCustomer($customerId, ['name' => 'New Name']);
      
    • Retrieve Customers:
      $customer = $subscriptionService->getCustomer($customerId);
      
  2. Subscription Lifecycle

    • Create Subscriptions:
      $subscription = $subscriptionService->createSubscription($customerId, 'price_id', [
          'trial_period_days' => 7,
      ]);
      
    • Cancel/Resume Subscriptions:
      $subscriptionService->cancelSubscription($subscriptionId);
      $subscriptionService->resumeSubscription($subscriptionId);
      
    • Update Subscription Plan:
      $subscriptionService->updateSubscription($subscriptionId, 'new_price_id');
      
  3. Webhook Handling

    • Controller Implementation:
      use Advancingu\StripeSubscriptionBundle\Controller\StripeWebhookController;
      
      class StripeWebhookController extends AbstractStripeWebhookController
      {
          protected function handleEvent($event)
          {
              switch ($event->type) {
                  case 'invoice.payment_succeeded':
                      // Handle successful payment
                      break;
                  case 'invoice.payment_failed':
                      // Handle failed payment
                      break;
                  case 'customer.subscription.deleted':
                      // Handle subscription cancellation
                      break;
              }
          }
      }
      
    • Event Mapping: Override getEventHandlers() in your controller to customize event responses:
      protected function getEventHandlers()
      {
          return [
              'invoice.payment_succeeded' => [$this, 'handlePaymentSucceeded'],
              'customer.subscription.deleted' => [$this, 'handleSubscriptionDeleted'],
          ];
      }
      
  4. Integration with Laravel Models

    • Attach Subscriptions to Eloquent Models: Use traits or services to link subscriptions to your models:
      use Advancingu\StripeSubscriptionBundle\Traits\HasStripeSubscription;
      
      class User extends Model
      {
          use HasStripeSubscription;
      }
      
      Then access subscriptions via:
      $user->stripeSubscription()->create($priceId);
      
  5. Testing

    • Mock Stripe API: Use stripe-php mocking libraries or the bundle’s test utilities:
      $this->mockStripeService()->shouldReceive('createCustomer')->once()->andReturn($mockCustomer);
      

Gotchas and Tips

Pitfalls

  1. Webhook Verification

    • Issue: Webhook events may fail silently if the STRIPE_WEBHOOK_SECRET is incorrect or missing.
    • Fix: Verify the secret in .env and ensure the route is protected:
      public function handleWebhook(Request $request)
      {
          $payload = $request->getContent();
          $sigHeader = $request->header('Stripe-Signature');
          $event = \Stripe\Webhook::constructEvent($payload, $sigHeader, config('stripe.webhook_secret'));
      }
      
  2. Customer ID Mismatch

    • Issue: Using a Laravel model’s id directly as Stripe’s customer field can cause conflicts if IDs are reused or deleted.
    • Fix: Use a separate field (e.g., stripe_customer_id) in your model to store Stripe’s customer ID.
  3. Subscription Sync Delays

    • Issue: Stripe’s webhooks may not fire immediately for subscription updates (e.g., trial ends).
    • Fix: Implement a cron job to sync subscriptions periodically:
      $subscriptionService->syncAllSubscriptions();
      
  4. Price ID Hardcoding

    • Issue: Hardcoding price_id in controllers or services reduces flexibility.
    • Fix: Fetch prices dynamically:
      $price = $subscriptionService->getPrice('product_id', ['interval' => 'month']);
      $subscription = $subscriptionService->createSubscription($customerId, $price->id);
      
  5. Error Handling

    • Issue: Stripe API errors (e.g., invalid price_id) may not be caught gracefully.
    • Fix: Wrap API calls in try-catch blocks:
      try {
          $subscription = $subscriptionService->createSubscription($customerId, $priceId);
      } catch (\Stripe\Exception\ApiErrorException $e) {
          Log::error('Stripe error: ' . $e->getMessage());
          throw new \Exception('Failed to create subscription');
      }
      

Tips

  1. Configuration Overrides Customize the bundle’s behavior via config/stripe_subscription.php:

    'webhook_endpoint' => '/custom/webhook/endpoint',
    'default_currency' => 'eur',
    'sync_cron_frequency' => 'daily', // 'daily', 'weekly', or custom
    
  2. Logging Enable debug logging for Stripe events:

    'logging' => [
        'enabled' => true,
        'channel' => 'stripe',
    ],
    

    Configure the channel in config/logging.php.

  3. Testing Webhooks Locally Use Stripe CLI to test webhooks:

    stripe listen --forward-to localhost:8000/stripe/webhook
    
  4. Extending the Bundle

    • Custom Services: Create a service that extends SubscriptionService:
      class CustomSubscriptionService extends SubscriptionService
      {
          public function customCreateSubscription($customerId, $priceId, array $options = [])
          {
              $options['metadata']['custom_field'] = 'value';
              return parent::createSubscription($customerId, $priceId, $options);
          }
      }
      
    • Event Listeners: Dispatch custom events after webhook handling:
      event(new SubscriptionUpdated($subscription));
      
  5. Performance

    • Batch Operations: Use syncAllSubscriptions() sparingly (e.g., during off-peak hours) to avoid rate limits.
    • Caching: Cache Stripe API responses for read-heavy operations:
      $price = Cache::remember("stripe_price_{$priceId}", now()->addHours(1), function () use ($priceId) {
          return $subscriptionService->getPrice($priceId);
      });
      
  6. Migration Notes

    • Existing Subscriptions: Migrate old subscriptions to Stripe’s API before using the bundle:
      $subscriptionService->migrateSubscription($oldSubscriptionData);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui