Skip to main content

Documentation Index

Fetch the complete documentation index at: https://danestvesllc-2b77d201.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Once a subscription exists in your database, Laravel Polar gives you a rich set of methods to inspect its state, change the plan, handle cancellation, and query across all subscriptions. All state-changing methods call the Polar API and immediately sync the updated status back to your local Subscription record — your database is always consistent.
Quick reference: valid() = usable right now. subscribed() = same check from the user model. cancelled() = marked for cancellation. onGracePeriod() = cancelled but still active until period ends.

Checking subscription status

valid()

Returns true if the subscription is active, on trial, past due, or within its grace period. This is the broadest “is the subscription usable?” check:
if ($user->subscription()->valid()) {
    // Subscription is in a usable state
}

subscribed()

A convenience wrapper on the billable model. Equivalent to calling subscription()->valid() without loading the model first:
if ($user->subscribed()) {
    // ...
}

cancelled()

Returns true when Polar has marked the subscription as canceled (status canceled):
if ($user->subscription()->cancelled()) {
    // Subscription has been canceled
}

onGracePeriod()

A canceled subscription may still have time remaining in the current billing period. onGracePeriod() returns true when the subscription is canceled but ends_at is still in the future:
if ($user->subscription()->onGracePeriod()) {
    // Still has access until the billing period ends
}

pastDue()

Returns true when a recurring payment has failed and the subscription is awaiting retry:
if ($user->subscription()->pastDue()) {
    // Prompt the customer to update their payment method
}
A past-due subscription is still considered valid by valid(). Polar retries failed payments automatically.

Checking the subscribed product

To verify the subscription is currently on a specific product, use hasProduct():
if ($user->subscription()->hasProduct('product_id_123')) {
    // Subscription is on this product
}
For a combined valid + product check directly on the billable, use subscribedToProduct():
if ($user->subscribedToProduct('product_id_123')) {
    // Valid subscription on this product
}

Swapping plans

When a customer wants to upgrade, downgrade, or change billing cadence, call swap() with the new product ID. The change takes effect at the next billing cycle and uses proration by default:
$user->subscription()->swap('new_product_id');
To apply the new plan and generate an invoice immediately, use swapAndInvoice():
$user->subscription()->swapAndInvoice('new_product_id');
swap() prorates the change at the next billing cycle by default. swapAndInvoice() prorates and invoices immediately, charging any difference right away.

Cancelling a subscription

Call cancel() to schedule a subscription for cancellation at the end of the current billing period:
$user->subscription()->cancel();
Polar does not support immediate cancellation. After calling cancel(), the subscription enters a grace period: the ends_at column is updated to the end of the current period, and the status becomes canceled. The customer retains access until ends_at passes.
if ($user->subscription()->onGracePeriod()) {
    // Customer can still access features until the period ends
}

Resuming a subscription

If a customer changes their mind during the grace period, call resume() to reinstate the subscription:
$user->subscription()->resume();
resume() only works while the subscription is still within its grace period. Once ends_at has passed and the subscription becomes expired, it cannot be resumed and the customer must start a new subscription.

Applying and removing discounts

Apply a discount to a subscription so it takes effect on the next billing cycle:
$user->subscription()->applyDiscount('disc_xxx');
Remove an active discount:
$user->subscription()->removeDiscount();
Both methods call the Polar API and sync the updated subscription locally. The discount change is reflected on the next invoice.

Querying subscriptions with scopes

The Subscription model ships with Eloquent query scopes for each status. Use them to filter subscriptions across your entire database or scoped to a specific billable.

Available scopes

Subscription::query()->active();
Subscription::query()->cancelled();
Subscription::query()->pastDue();
Subscription::query()->unpaid();
Subscription::query()->incomplete();
Subscription::query()->incompleteExpired();
Subscription::query()->onTrial();

Usage examples

use Danestves\LaravelPolar\Subscription;

// All active subscriptions across all users
$subscriptions = Subscription::query()->active()->get();

// All canceled subscriptions for a specific user
$subscriptions = $user->subscriptions()->cancelled()->get();

// Past-due subscriptions to notify customers about
$pastDue = Subscription::query()->pastDue()->get();
Combine scopes with Eloquent relationships for efficient queries. $user->subscriptions() returns a query builder you can chain any scope onto.