#How to use Polar with Convex

5 messages · Page 1 of 1 (latest)

deft fable
#

I just initiated a monorepo next js 15 and convex project. I started with ConvexAuth and now I am trying to implement Polar with a clean susbcription system. There is no recent documentation about that and the tutorials feel outdated.

ruby sapphireBOT
#

Hi @deft fable. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To use Polar with Convex in your Next.js 15 + Convex monorepo (with ConvexAuth), follow these up-to-date steps based on the latest official documentation and community guidance:


1. Install the Polar Component

In your Convex project, install the Polar component:

npm install @convex-dev/polar

Then, register the component in your convex/convex.config.ts:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import polar from "@convex-dev/polar/convex.config";

const app = defineApp();
app.use(polar);

export default app;

Set your Polar organization token:

npx convex env set POLAR_ORGANIZATION_TOKEN <your_token>

Convex Polar Component


2. Initialize the Polar Client

In your Convex backend (e.g., convex/example.ts), initialize the Polar client:

import { Polar } from "@convex-dev/polar";
import { api, components } from "./_generated/api";

export const polar = new Polar(components.polar, {
  getUserInfo: async (ctx) => {
    const user = await ctx.runQuery(api.example.getCurrentUser);
    return {
      userId: user._id,
      email: user.email,
    };
  },
  products: {
    premiumMonthly: "product_id_from_polar",
    premiumYearly: "product_id_from_polar",
  },
  // Optionally set organizationToken, webhookSecret, server, etc.
});

Initialize the Polar client


3. Set Up Polar Webhooks

#
  • In the Polar dashboard, create a webhook with your Convex site URL + /polar/events (e.g., <https://your-app.convex.site/polar/events>).
  • Enable the following events: product.created, product.updated, subscription.created, subscription.updated.
  • Set the webhook secret in Convex:
npx convex env set POLAR_WEBHOOK_SECRET <your_webhook_secret>
  • Register the webhook handler in convex/http.ts:
import { httpRouter } from "convex/server";
import { polar } from "./example";

const http = httpRouter();
polar.registerRoutes(http as any);
export default http;

Set up Polar webhooks


4. Sync Existing Products (If Needed)

If you created products in Polar before setting up the Convex integration, you must sync them:

export const syncProducts = action({
  args: {},
  handler: async (ctx) => {
    await polar.syncProducts(ctx);
  },
});

API Reference: syncProducts


5. Add Subscription UI Components

Use the provided React components in your Next.js app:

import { CheckoutLink, CustomerPortalLink } from "@convex-dev/polar/react";
import { api } from "../convex/_generated/api";

// For new subscriptions
<CheckoutLink
  polarApi={api.example}
  productIds={[products.premiumMonthly.id, products.premiumYearly.id]}
  embed={false}
>
  Upgrade to Premium
</CheckoutLink>

// For managing existing subscriptions
<CustomerPortalLink
  polarApi={{ generateCustomerPortalUrl: api.example.generateCustomerPortalUrl }}
>
  Manage Subscription
</CustomerPortalLink>

Add subscription UI components


6. Access Subscription Data

Query subscription info in your Convex backend:

#
export const getCurrentUser = query({
  handler: async (ctx) => {
    const user = await ctx.db.query("users").first();
    if (!user) throw new Error("No user found");

    const subscription = await polar.getCurrentSubscription(ctx, {
      userId: user._id,
    });

    return {
      ...user,
      subscription,
      isFree: !subscription,
      isPremium:
        subscription?.productKey === "premiumMonthly" ||
        subscription?.productKey === "premiumYearly",
    };
  },
});

Access subscription data


7. Handle Subscription Changes

You can change or cancel subscriptions using the provided actions:

const changeSubscription = useAction(api.example.changeCurrentSubscription);
await changeSubscription({ productId: "new_product_id" });

const cancelSubscription = useAction(api.example.cancelCurrentSubscription);
await cancelSubscription({ revokeImmediately: true });

Handle subscription changes


Note:

  • If you need to backfill products, use the syncProducts action as described above.
  • The Polar component is actively maintained, and recent updates have addressed common issues like backfilling and webhook handling.

If you follow these steps, you’ll have a clean, up-to-date subscription system with Polar and Convex in your Next.js 15 monorepo. If you encounter any issues, check the official example app or reach out on Discord for support.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: