Skip to main content

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

useProviderPayment

A data aggregation hook that combines payment history and subscription data from multiple payment providers (Stripe and LemonSqueezy) into a unified interface. Routes data through the configured payment provider and computes billing statistics.

Source file: template/hooks/use-provider-payment.ts

Overview

useProviderPayment reads the active payment provider from the application configuration, then fetches and merges data from useBillingData (Stripe-centric subscription and payment history) and useLemonSqueezyCheckouts (LemonSqueezy checkout records). It normalizes LemonSqueezy checkout records into the same shape as Stripe payment records, then exposes only the data relevant to the configured provider. The hook also computes summary statistics such as total spent, active payment count, and monthly average.

Signature

function useProviderPayment(): UseProviderPaymentReturn

Parameters

None. This hook takes no arguments. The active payment provider is read from the application config via useConfig().pricing.provider.

Return Value

Provider Info

PropertyTypeDescription
providerPaymentProvider | undefinedThe configured payment provider ('stripe', 'lemonsqueezy', 'polar', or 'solidgate')

Payment Data

PropertyTypeDescription
paymentsPaymentRecord[]Payment records filtered to the configured provider
stripePaymentsPaymentRecord[]All Stripe-sourced payment records (regardless of active provider)
lemonSqueezyPaymentsTransformedCheckout[]All LemonSqueezy checkout records transformed into payment record shape
stripeTotalnumberSum of all Stripe payment amounts
lemonSqueezyTotalnumberSum of all LemonSqueezy payment amounts

Statistics

PropertyTypeDescription
totalSpentnumberSum of all payment amounts for the active provider
activePaymentsnumberCount of payments with status 'Paid' or 'active'
monthlyAveragenumbertotalSpent / totalPayments, or 0 if no payments exist
totalPaymentsnumberTotal number of payment records for the active provider

Subscription Data

PropertyTypeDescription
subscriptionSubscriptionInfo | undefinedSubscription information from useBillingData

Loading and Error States

PropertyTypeDescription
loadingbooleantrue if either billing data or LemonSqueezy checkouts are loading
isLoadingCheckoutsbooleanWhether LemonSqueezy checkouts are loading specifically
isErrorbooleanWhether the LemonSqueezy checkout query has an error
errorError | nullError object from the LemonSqueezy checkout query

Actions

PropertyTypeDescription
refresh() => voidRefresh all billing data (subscription + payments)
refreshSubscription() => voidRefresh only subscription data
refreshPayments() => voidRefresh only Stripe payment data
refreshCheckouts() => voidRefresh LemonSqueezy checkout data
updateFilters(filters: CheckoutFilters) => voidUpdate LemonSqueezy checkout query filters

Pagination (LemonSqueezy)

PropertyTypeDescription
paginationPaginationInfoCurrent pagination state for LemonSqueezy checkouts
hasMorebooleanWhether more LemonSqueezy checkout pages are available
nextPage() => voidNavigate to the next page of LemonSqueezy checkouts
prevPage() => voidNavigate to the previous page
goToPage(page: number) => voidJump to a specific page

Flags

PropertyTypeDescription
isRefreshingbooleanWhether any billing data refresh is in progress
isRefreshingSubscriptionbooleanWhether subscription refresh is in progress
isRefreshingPaymentsbooleanWhether payment history refresh is in progress
hasPaymentHistorybooleanWhether the user has any payments for the active provider
hasSubscriptionHistorybooleanWhether the user has any subscription history records

Implementation Details

Provider Routing

The providerPayments computed value uses the configured provider to decide which data set to expose:

provider === 'stripe'       -> Stripe payment records from useBillingData
provider === 'lemonsqueezy' -> Transformed LemonSqueezy checkout records
other -> Empty array

LemonSqueezy Checkout Transformation

LemonSqueezy checkouts are transformed into a normalized payment record shape with:

  • id prefixed with ls_ to avoid collisions
  • paymentProvider set to 'lemonsqueezy'
  • status mapped from 'active' to 'Paid'
  • Additional LemonSqueezy-specific fields preserved (checkoutId, productName, variantName, storeId, metadata)

Statistics Computation

All statistics (totalSpent, activePayments, monthlyAverage) are computed from providerPayments, meaning they reflect only the active provider's data. Provider-specific totals (stripeTotal, lemonSqueezyTotal) are computed independently for comparison views.

Usage Examples

Billing dashboard

import { useProviderPayment } from '@/hooks/use-provider-payment';

function BillingDashboard() {
const {
provider,
payments,
totalSpent,
activePayments,
monthlyAverage,
subscription,
loading,
refresh,
} = useProviderPayment();

if (loading) return <Skeleton />;

return (
<div>
<h2>Billing ({provider})</h2>

<div className="grid grid-cols-3 gap-4">
<StatCard label="Total Spent" value={`$${(totalSpent / 100).toFixed(2)}`} />
<StatCard label="Active Payments" value={activePayments} />
<StatCard label="Monthly Average" value={`$${(monthlyAverage / 100).toFixed(2)}`} />
</div>

{subscription?.hasActiveSubscription && (
<div className="mt-4">
<p>Current Plan: {subscription.currentSubscription?.planName}</p>
<p>Next Billing: {subscription.currentSubscription?.nextBillingDate}</p>
</div>
)}

<button onClick={refresh} className="mt-4">Refresh</button>

<PaymentHistoryTable payments={payments} />
</div>
);
}

Provider comparison view

import { useProviderPayment } from '@/hooks/use-provider-payment';

function ProviderComparison() {
const { stripePayments, lemonSqueezyPayments, stripeTotal, lemonSqueezyTotal } =
useProviderPayment();

return (
<div className="grid grid-cols-2 gap-8">
<div>
<h3>Stripe</h3>
<p>Payments: {stripePayments.length}</p>
<p>Total: ${(stripeTotal / 100).toFixed(2)}</p>
</div>
<div>
<h3>LemonSqueezy</h3>
<p>Payments: {lemonSqueezyPayments.length}</p>
<p>Total: ${(lemonSqueezyTotal / 100).toFixed(2)}</p>
</div>
</div>
);
}

Payment history with empty state

import { useProviderPayment } from '@/hooks/use-provider-payment';

function PaymentHistory() {
const { payments, hasPaymentHistory, loading, provider } = useProviderPayment();

if (loading) return <Spinner />;

if (!hasPaymentHistory) {
return <EmptyState message={`No payment history found for ${provider}.`} />;
}

return (
<table>
<thead>
<tr>
<th>Date</th>
<th>Plan</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{payments.map((payment) => (
<tr key={payment.id}>
<td>{new Date(payment.date).toLocaleDateString()}</td>
<td>{payment.plan}</td>
<td>${(payment.amount / 100).toFixed(2)}</td>
<td>{payment.status}</td>
</tr>
))}
</tbody>
</table>
);
}

Requirements

DependencyPurpose
reactuseMemo for computed values
@/app/[locale]/configuseConfig to read the active payment provider
./use-lemonsqueezy-checkoutsLemonSqueezy checkout data and pagination
./use-billing-dataStripe subscription and payment history
@/lib/constantsPaymentProvider enum