Subscription Flow
How merchants subscribe to your plugin's pricing plans using the App Bridge billing API.
Overview
Subscriptions are initiated from inside your plugin using the App Bridge billing API. The platform handles the approval page, payment setup, and lifecycle events. Your plugin reads and reacts to the subscription state.
Step 1 — Display Available Plans
Fetch your plans and show them to the merchant:
import { useAppBridge } from "@whatalo/plugin-sdk/bridge";
function PricingPage() {
const bridge = useAppBridge();
async function loadPlans() {
const plans = await bridge.billing.getPlans();
// plans: BillingPlanResponse[]
// [{ slug, name, price, currency, interval, trialDays, features, isPopular }]
}
}Step 2 — Request a Subscription
Call requestSubscription with a plan slug. This sends a billing action to the admin host, which redirects the merchant to an approval page.
async function handleSubscribe(planSlug: string) {
try {
await bridge.billing.requestSubscription(planSlug);
// The host handles the redirect — this function may not return
// if the page navigates away during approval
} catch (error) {
bridge.toast.show("Could not start subscription", { variant: "error" });
}
}The merchant sees the plan details, price, and trial information, then confirms or cancels. Your plugin does not need to handle the approval redirect — the platform manages it.
Step 3 — Check Subscription Status
After the merchant approves, read the active subscription:
const sub = await bridge.billing.getSubscription();
if (!sub) {
// No active subscription for this installation
return;
}
console.log(sub.status); // "trialing", "active", etc.
console.log(sub.planSlug); // "pro"
console.log(sub.planName); // "Pro"
console.log(sub.trialEndsAt); // ISO date string or null
console.log(sub.cancelAtPeriodEnd); // booleanSubscription States
| Status | Description |
|---|---|
pending | Awaiting merchant approval on the confirmation page |
trialing | In the free trial period — merchant is not charged |
active | Billing is active, merchant is being charged each cycle |
past_due | A payment failed — billing system is retrying |
canceled | Subscription has ended |
expired | Trial or billing period ended without renewal |
Cancellation
Cancel a subscription at the end of the current billing period. The merchant keeps full access until the period ends:
await bridge.billing.cancelSubscription();After cancellation, sub.cancelAtPeriodEnd is true and sub.canceledAt contains the timestamp. The merchant is not charged again after the current period.
Reactivation
While the subscription is still in its active period, the merchant can undo a cancellation:
await bridge.billing.reactivateSubscription();After reactivation, cancelAtPeriodEnd returns to false.
Plan Switching
Switch the merchant to a different plan. Proration is applied: the merchant receives credit for unused time on the current plan, applied immediately toward the new plan:
await bridge.billing.switchPlan("enterprise");Subscription Response Shape
interface BillingSubscriptionResponse {
planSlug: string;
planName: string;
/** "pending" | "trialing" | "active" | "past_due" | "canceled" | "expired" */
status: string;
trialEndsAt: string | null; // ISO timestamp or null
currentPeriodEnd: string | null; // ISO timestamp or null
cancelAtPeriodEnd: boolean;
canceledAt: string | null; // ISO timestamp or null
}Error Handling
All billing methods throw on failure. Wrap them in try/catch:
try {
await bridge.billing.cancelSubscription();
bridge.toast.show("Subscription cancelled", { variant: "success" });
} catch (error) {
bridge.toast.show("Could not cancel subscription", { variant: "error" });
}Billing methods do not return { success: false } — they throw, so standard error handling applies.
Gating Features by Subscription
Use getSubscription to conditionally render premium features:
function Dashboard() {
const bridge = useAppBridge();
const [sub, setSub] = useState<BillingSubscriptionResponse | null>(null);
useEffect(() => {
bridge.billing.getSubscription().then(setSub);
}, []);
const isActive = sub?.status === "active" || sub?.status === "trialing";
return isActive ? <PremiumContent /> : <UpgradePrompt />;
}Plans & Pricing
Create up to 5 active pricing plans per plugin through the Developer Portal. Define pricing type, billing interval, trial period, and feature list.
Revenue & Payouts
Track your plugin earnings and request payouts through the Developer Portal. Understand commission calculation and payout requirements.