Subscriptions
AuthGate manages the full subscription lifecycle — from plan creation to cancellation. Plans and prices are defined once in the dashboard, and users move through them via your application's UI or directly via the API.
Plans and prices
A plan is a product offering (e.g. "Starter", "Pro", "Enterprise"). Each plan has one or more prices that define the billing interval and amount.
Creating a plan
In the AuthGate dashboard, navigate to Billing → Plans → New Plan. Set:
- Name — displayed to users (e.g. "Pro")
- Description — optional marketing copy
- Features — list of feature flags this plan grants (used for entitlements)
Adding prices
Each plan can have multiple prices for different billing intervals. Three pricing models are supported:
| Model | Description |
|---|---|
| Recurring | Fixed amount charged every billing period (monthly or annually) |
| Metered | Charge based on usage reported during the billing period |
| Tiered | Price per unit changes based on total quantity (volume or graduated) |
Example price configuration
{
"nickname": "Pro Monthly",
"amount": 2900,
"currency": "usd",
"interval": "month",
"model": "recurring"
}
Amounts are always in the smallest currency unit (cents for USD).
Subscription lifecycle
create → trialing (optional) → active → past_due → canceled
↓
paused
| Status | Description |
|---|---|
trialing | User is in a free trial period; no charge yet |
active | Subscription is current and paid |
past_due | Payment failed; grace period before cancellation |
paused | Subscription manually paused; no billing occurs |
canceled | Subscription ended; access should be revoked |
Creating a subscription
Subscriptions are created via the checkout flow. Your application redirects users to the hosted checkout session or renders the <CheckoutForm /> component. On success, AuthGate creates the subscription and fires a subscription.created webhook.
See SDK Components for the checkout UI and Billing API Endpoints for the raw API.
Canceling a subscription
Subscriptions can be canceled immediately or at the end of the current billing period. Cancel-at-period-end is the default — users retain access until the period closes.
curl -X POST https://your-authgate-instance.com/api/proxy/billing/subscription/cancel \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{ "at_period_end": true }'
Pausing a subscription
Pausing stops the billing cycle without canceling the subscription. The user loses access while paused. Resume resumes billing from the pause date.
curl -X POST https://your-authgate-instance.com/api/proxy/billing/subscription/pause \
-H "Authorization: Bearer <session_token>"
Plan changes and proration
When a user upgrades or downgrades, AuthGate calculates proration automatically:
- Upgrade — the user is charged for the remaining days on the new plan, minus a credit for unused days on the old plan
- Downgrade — a credit is applied toward the next invoice; no immediate charge
Proration is calculated at the moment of the plan change and appears as a line item on the next invoice.
Proration only applies to recurring flat-rate prices. Metered and tiered prices are always billed at period end based on actual usage.
Trial periods
Trials are configured per plan in the dashboard. Set the trial duration in days; new subscribers on that plan automatically receive a trial before their first charge.
- Users in
trialingstatus have full access to plan features via entitlements - No payment method is required to start a trial (configurable)
- If no payment method is collected and the trial ends, the subscription moves to
canceled - A
subscription.trial_endingwebhook fires 3 days before trial expiry
Reading subscriptions in React
Use the useSubscription hook from @auth-gate/react to read the current user's subscription in any client component:
import { useSubscription } from "@auth-gate/react";
function SubscriptionStatus() {
const { subscription, loading, error } = useSubscription();
if (loading) return <p>Loading...</p>;
if (error) return <p>Failed to load subscription.</p>;
if (!subscription) return <p>No active subscription.</p>;
return (
<div>
<p>Plan: {subscription.plan.name}</p>
<p>Status: {subscription.status}</p>
<p>Renews: {new Date(subscription.current_period_end).toLocaleDateString()}</p>
</div>
);
}
The hook fetches from GET /api/proxy/billing/subscription and caches the result. It returns null for subscription when the user has no active or trialing subscription.