> ## Documentation Index
> Fetch the complete documentation index at: https://docs.subscribd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks and Events

> React to billing milestones with Laravel events and lifecycle hooks

# Hooks and Events

Subscribd fires Laravel events at every significant billing milestone. Listen to them from `AppServiceProvider`, a dedicated `EventServiceProvider`, or anywhere you register listeners in your application.

## Registering listeners

```php theme={null}
use Illuminate\Support\Facades\Event;
use Pixelworxio\Subscribd\Events\SubscriptionCreated;

// AppServiceProvider::boot()
Event::listen(SubscriptionCreated::class, function (SubscriptionCreated $event) {
    // $event->subscription — the created Subscription model
    // $event->subscription->billable — the subscriber
});
```

Or use a dedicated listener class:

```php theme={null}
Event::listen(SubscriptionCreated::class, SendWelcomeEmail::class);
```

## Event reference

### Subscription lifecycle

| Event                  | Fired when                                         | Key properties                          |
| ---------------------- | -------------------------------------------------- | --------------------------------------- |
| `SubscriptionCreated`  | A new subscription is created and active           | `$subscription`                         |
| `SubscriptionUpdated`  | Any attribute on a subscription changes            | `$subscription`, `$changes`             |
| `SubscriptionCanceled` | A subscription is canceled (grace or immediate)    | `$subscription`                         |
| `SubscriptionResumed`  | A canceled subscription in grace period is resumed | `$subscription`                         |
| `SubscriptionExpired`  | A subscription reaches end of life with no renewal | `$subscription`                         |
| `SubscriptionPaused`   | A subscription is paused                           | `$subscription`                         |
| `SubscriptionUnpaused` | A paused subscription is resumed                   | `$subscription`                         |
| `SubscriptionPastDue`  | A subscription enters past due status              | `$subscription`                         |
| `PlanSwapped`          | A subscription's plan changes                      | `$subscription`, `$oldPlan`, `$newPlan` |

### Trial events

| Event            | Fired when                                      | Key properties                    |
| ---------------- | ----------------------------------------------- | --------------------------------- |
| `TrialStarted`   | A subscription is created with a trial period   | `$subscription`                   |
| `TrialEnding`    | Trial is within the `notify_days_before` window | `$subscription`, `$trialEndsAt`   |
| `TrialEnded`     | Trial period expires                            | `$subscription`                   |
| `TrialConverted` | Trial is converted to an active subscription    | `$subscription`                   |
| `TrialCanceled`  | Trial is canceled before converting             | `$subscription`                   |
| `TrialExtended`  | Trial end date is extended                      | `$subscription`, `$extendedUntil` |

### Payment events

| Event                   | Fired when                                                | Key properties                |
| ----------------------- | --------------------------------------------------------- | ----------------------------- |
| `InvoicePaid`           | An invoice is successfully paid                           | `$invoice`                    |
| `InvoicePaymentFailed`  | An invoice payment attempt fails                          | `$invoice`                    |
| `InvoiceCreated`        | A new invoice is generated                                | `$invoice`                    |
| `InvoiceRefunded`       | A refund is issued on a paid invoice                      | `$invoice`, `$amount`         |
| `PaymentRetryFailed`    | A dunning retry attempt fails                             | `$invoice`, `$attempt`        |
| `PaymentMethodExpiring` | A payment method is within `notify_days_before` of expiry | `$billable`, `$paymentMethod` |

### Coupon events

| Event           | Fired when                            | Key properties             |
| --------------- | ------------------------------------- | -------------------------- |
| `CouponApplied` | A coupon is applied to a subscription | `$subscription`, `$coupon` |
| `CouponExpired` | An applied coupon reaches its expiry  | `$subscription`, `$coupon` |

## All events namespace

All events live under `Pixelworxio\Subscribd\Events\`:

```php theme={null}
use Pixelworxio\Subscribd\Events\SubscriptionCreated;
use Pixelworxio\Subscribd\Events\SubscriptionCanceled;
use Pixelworxio\Subscribd\Events\SubscriptionExpired;
use Pixelworxio\Subscribd\Events\SubscriptionPastDue;
use Pixelworxio\Subscribd\Events\PlanSwapped;
use Pixelworxio\Subscribd\Events\TrialStarted;
use Pixelworxio\Subscribd\Events\TrialEnding;
use Pixelworxio\Subscribd\Events\TrialConverted;
use Pixelworxio\Subscribd\Events\InvoicePaid;
use Pixelworxio\Subscribd\Events\InvoicePaymentFailed;
use Pixelworxio\Subscribd\Events\PaymentRetryFailed;
use Pixelworxio\Subscribd\Events\CouponApplied;
```

## Using observers

For more complex scenarios, register a model observer on `Subscription` or `Invoice` directly:

```php theme={null}
use Pixelworxio\Subscribd\Models\Subscription;

Subscription::observe(SubscriptionObserver::class);
```

## Lifecycle hooks

For lightweight callbacks that don't warrant a full listener, use the action hooks API:

```php theme={null}
use Pixelworxio\Subscribd\Actions\CreateSubscription;

CreateSubscription::before(function (Billable $billable, Plan $plan, array $options) {
    // Runs before the action executes
    // Return false to abort
});

CreateSubscription::after(function (Subscription $subscription) {
    // Runs after the subscription is created
});
```

Hook callbacks receive the same arguments as the action's `execute()` method. `before` callbacks can abort execution by returning `false`. `after` callbacks receive the action's return value.

Available action hooks:

| Action                         | Hook receives                                               |
| ------------------------------ | ----------------------------------------------------------- |
| `CreateSubscription::before`   | `Billable $billable, Plan $plan, array $options`            |
| `CreateSubscription::after`    | `Subscription $subscription`                                |
| `SwapPlan::before`             | `Subscription $subscription, Plan $newPlan, array $options` |
| `SwapPlan::after`              | `Subscription $subscription`                                |
| `CancelSubscription::before`   | `Subscription $subscription, bool $immediately`             |
| `CancelSubscription::after`    | `Subscription $subscription`                                |
| `ResumeSubscription::before`   | `Subscription $subscription`                                |
| `ResumeSubscription::after`    | `Subscription $subscription`                                |
| `PauseSubscription::before`    | `Subscription $subscription, array $options`                |
| `PauseSubscription::after`     | `Subscription $subscription`                                |
| `ConvertTrialToActive::before` | `Subscription $subscription`                                |
| `ConvertTrialToActive::after`  | `Subscription $subscription`                                |

## Testing events

Use Laravel's `Event::fake()` to assert events are dispatched in tests:

```php theme={null}
use Pixelworxio\Subscribd\Events\SubscriptionCreated;
use Pixelworxio\Subscribd\Events\PlanSwapped;
use Illuminate\Support\Facades\Event;

it('fires SubscriptionCreated on subscribe', function () {
    Event::fake([SubscriptionCreated::class]);

    $user = User::factory()->create();
    $plan = Plan::factory()->create(['key' => 'pro']);

    app(\Pixelworxio\Subscribd\Actions\CreateSubscription::class)->execute($user, $plan);

    Event::assertDispatched(SubscriptionCreated::class, function ($event) use ($user) {
        return $event->subscription->billable->is($user);
    });
});
```

## Next steps

* **[Webhooks](/advanced/webhooks)** — Gateway events that trigger these Subscribd events
* **[Testing](/advanced/testing)** — Testing billing flows with `Event::fake()`
* **[Dunning](/advanced/dunning)** — Events fired during the payment retry cycle
