llms.txt
llms.txt

Polar Integration

Polar is a good fit for SaaS products, open-source sponsorships, digital products, and entitlement-aware app features.

Install from the CLI

farm add integration polar --ui

Config-first setup

src/lib/integrations.ts
import { polar } from "@farm.js/integrations/polar";export const integrations = {  billing: polar({    accessToken: process.env.POLAR_ACCESS_TOKEN,    billing: {      resolveOwner(ctx) {        const userId = ctx.req.get<string>("user.id");        return userId ? { id: userId, kind: "user" } : null;      },    },  }),};

POLAR_WEBHOOK_SECRET is read from the environment when webhook routes are configured.

With no instance, Farm constructs the Polar SDK from accessToken and server. The token can be passed directly or read from POLAR_ACCESS_TOKEN.

Choose SDK ownership

Let Farm construct Polar

Use the config-first example above for the common path. Farm owns SDK construction, while the application still supplies billing ownership, products, meters, routes, and webhook behavior.

Provide an application-owned instance

import { Polar } from "@polar-sh/sdk";import { polar } from "@farm.js/integrations/polar";const polarClient = new Polar({  accessToken: process.env.POLAR_ACCESS_TOKEN!,  server: "sandbox",});export const billing = polar({  instance: polarClient,  server: "sandbox",  billing: {    resolveOwner: () => null,  },});

Farm uses the supplied SDK directly, so the integration does not require accessToken. server still describes the integration environment and defaults from POLAR_SERVER. When both an instance and token are supplied, the instance wins.

Usage

const checkout = await api.billing.checkout.post({  body: {    productId: "pro",    customerEmail: user.email,    successPath: "/dashboard",  },});

Database-backed billing

Polar callbacks can read and write relational records through ctx.args.db, so webhook snapshots, subscription state, and customer entitlement checks share the same database-agnostic integration layer. This path is separate from KV storage.

What Polar adds

Area Details
Products Public product metadata for pricing and account screens.
Checkout Polar checkout sessions for one-time and subscription products.
Portal Customer sessions for billing management.
Billing status Current customer, plan, features, limits, and active product state.
Usage Meter and entitlement helpers for usage-aware products.
Webhooks Subscription and order events that update local billing state.

Common callers

const products = await api.billing.products.get();const status = await api.billing.status.get();const checkout = await api.billing.checkout.post({  body: {    productId: "pro",    successPath: "/dashboard",    cancelPath: "/pricing",  },});

Portal flow

const portal = await api.billing.portal.post({  body: {    returnTo: "/settings/billing",  },});if (portal.data?.redirectTo) {  window.location.href = portal.data.redirectTo;}

When Polar is a good fit

Polar works especially well when the product is developer-facing, open-source, sponsor-backed, or selling digital access. The Farm integration keeps the same caller shape as other billing providers, so moving between Stripe, Autumn, and Polar does not force your app UI to learn a new local API style.

Production notes

  • Set POLAR_ACCESS_TOKEN, POLAR_WEBHOOK_SECRET, POLAR_SERVER, and APP_BASE_URL.
  • Use sandbox/server config for local testing and production config for live billing.
  • Store the external customer ID with the billing owner so portal and status reads stay stable.
  • Test checkout return URLs, portal return URLs, webhook signatures, and entitlement checks.