Skip to content

WebhookController fails to clear trial_ends_at when trial_end is null in Stripe payload #1824

@xjavun

Description

@xjavun

Cashier Stripe Version

16.3.0

Laravel Version

12.53.0

PHP Version

8.4.18

Database Driver & Version

No response

Description

Description:
The handleCustomerSubscriptionUpdated method in WebhookController (Line 161 in v16.0) uses isset($data['trial_end']) to determine if the local trial_ends_at column should be updated.

When a subscription's trial ends in Stripe, the webhook payload contains "trial_end": null. In PHP, isset(null) returns false. Consequently, the update block is skipped, and the local trial_ends_at column is never cleared.

Impact:

The local database retains a stale, future timestamp for a trial that has already ended in Stripe.
onTrial() returns true erroneously if the stale timestamp is still in the future relative to the server/test-clock.
Mutations like resume() fail with a 400 error from Stripe because Cashier attempts to re-send the stale (now invalid) trial_end date.

Suggested Fix:
Change the check to array_key_exists('trial_end', $data) or use ! is_null($data['trial_end']) if coupled with an explicit else to nullify the column.

Steps To Reproduce

  1. Create a subscription with a trial period.
  2. Wait for the trial to end in Stripe (either naturally or by using a Stripe Test Clock to advance time).
  3. Stripe sends a customer.subscription.updated webhook. The payload contains "status": "active" and "trial_end": null.
  4. Cashier processes the webhook via WebhookController@handleCustomerSubscriptionUpdated.
  5. Check the subscriptions table in the database.
  6. Actual Result: The trial_ends_at column still contains the old timestamp because isset($data['trial_end']) returns false when the value is null.
  7. Expected Result: The trial_ends_at column should be updated to NULL to reflect the actual state in Stripe.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions