Gate a feature behind a plan
Wrap any component in <Paywall> and enforce it for real server-side.
<Paywall> (from @vibemonetize/react) gates on exactly one of a feature slug or a meter slug — never both. It renders children while the gate is open, and fallback once it isn't.
1. Mount the provider once
npx vibemonetize init does this for you, but here it is explicitly — one provider near the root of your app, in both Next App Router and Vite:
import { MonetizeProvider } from "@vibemonetize/react";
<MonetizeProvider
appId={process.env.NEXT_PUBLIC_VIBEMONETIZE_APP_ID!}
apiUrl="https://api.vibemonetize.dev"
publishableKey={process.env.NEXT_PUBLIC_VIBEMONETIZE_PUBLISHABLE_KEY!}
>
<App />
</MonetizeProvider>2. Gate the feature
import { Paywall, CheckoutButton } from "@vibemonetize/react";
function ExportPanel() {
return (
<Paywall feature="export" fallback={<CheckoutButton planId="01H...">Upgrade to export</CheckoutButton>}>
<ExportButton />
</Paywall>
);
}A feature slug is a plain on/off flag defined on a plan's grants. Client-side, <Paywall> fails open: if the API is unreachable, or there's no provider mounted yet, it renders children rather than locking users out.
3. Enforce it for real, server-side
Client gates are advisory. Anything that actually matters — a privileged API route, a paid download — must be enforced with @vibemonetize/server, which fails closed:
import { createClient } from "@vibemonetize/server";
const monetize = createClient({ appId: process.env.VIBEMONETIZE_APP_ID! });
export async function POST(req: Request) {
const token = req.headers.get("x-vibemonetize-token") ?? "";
// Throws payment_required / forbidden / token_expired / unauthorized.
const claims = await monetize.requireEntitlement(token, "export");
// ... handle the request using `claims` ...
}See the entitlement tokens guide for how that token gets from the provider to your server route. No server at all? A pure-client Vite app can still enforce this with a single copy-paste edge function — see enforce the paywall with one edge function.