Documentation Index
Fetch the complete documentation index at: https://docs.billingos.dev/llms.txt
Use this file to discover all available pages before exploring further.
Self-service billing reduces support tickets and increases customer satisfaction. BillingOS gives you a complete customer portal that handles plan changes, invoices, payment methods, and cancellations — all in a single component.
Drop-in customer portal
The CustomerPortal component gives your users a complete billing management interface:
import { CustomerPortal } from "@billingos/sdk";
export default function BillingPage() {
return <CustomerPortal mode="page" />;
}
That single line gives your customers:
- Current plan details and renewal date
- Upgrade and downgrade options with proration preview
- Invoice history with PDF downloads
- Add, remove, and change default payment methods
- Cancel and reactivate subscriptions
Display modes
The portal supports three modes for different UI patterns:
// Full-page billing section
<CustomerPortal mode="page" />
// Slide-in drawer from the right
<CustomerPortal mode="drawer" isOpen={open} onClose={() => setOpen(false)} />
// Centered modal dialog
<CustomerPortal mode="modal" isOpen={open} onClose={() => setOpen(false)} />
Handle events
<CustomerPortal
mode="page"
onSubscriptionUpdate={(subscription) => {
toast.success("Plan updated!");
}}
onSubscriptionCancel={() => {
toast.info("Subscription will cancel at end of period");
}}
onPaymentMethodAdd={() => {
toast.success("Payment method added");
}}
/>
See the full CustomerPortal reference for all props.
Using hooks for custom UIs
If you need a custom billing interface, use the subscription hooks directly.
Show current subscription
import { useSubscriptions } from "@billingos/sdk";
function CurrentPlan() {
const { data } = useSubscriptions();
const subscription = data?.data?.[0];
if (!subscription) return <p>No active plan</p>;
return (
<div>
<p>Plan: {subscription.price_id}</p>
<p>Status: {subscription.status}</p>
<p>Renews: {new Date(subscription.current_period_end).toLocaleDateString()}</p>
</div>
);
}
Upgrade or downgrade
import { useAvailablePlans, useChangePlan } from "@billingos/sdk";
function PlanSwitcher({ subscriptionId }: { subscriptionId: string }) {
const { data: plans } = useAvailablePlans(subscriptionId);
const { mutateAsync: changePlan } = useChangePlan();
const handleChange = async (newPriceId: string) => {
await changePlan({
subscriptionId,
input: {
new_price_id: newPriceId,
effective_date: "immediate",
},
});
};
return (
<div>
<h3>Available upgrades</h3>
{plans?.available_upgrades.map((plan) => (
<button key={plan.price_id} onClick={() => handleChange(plan.price_id)}>
{plan.name} — ${plan.amount / 100}/mo
</button>
))}
</div>
);
}
Cancel subscription
import { useCancelSubscription } from "@billingos/sdk";
function CancelButton({ subscriptionId }: { subscriptionId: string }) {
const { mutateAsync: cancel, isPending } = useCancelSubscription(subscriptionId);
return (
<button
onClick={() => cancel({ immediately: false })}
disabled={isPending}
>
Cancel at end of billing period
</button>
);
}
Reactivate cancelled subscription
import { useReactivateSubscription } from "@billingos/sdk";
function ReactivateButton({ subscriptionId }: { subscriptionId: string }) {
const { mutateAsync: reactivate } = useReactivateSubscription(subscriptionId);
return <button onClick={() => reactivate()}>Keep my plan</button>;
}