docs/ts/develop/integrations/polar.md
Polar handles payments, subscriptions, and license keys as your Merchant of Record. This guide shows how to integrate Polar with an Encore application.
To get started quickly, create a new app from the example:
$ encore app create --example=ts/polar
Or follow the steps below to add Polar to an existing Encore app.
<Callout type="info">If you haven't installed Encore yet, see the installation guide first.
</Callout>$ npm install @polar-sh/sdk
Before writing code, you'll need to set up a few things in the Polar dashboard (use the sandbox for development):
/webhooks/polar. For local development, use a tunnel like ngrok to expose your local server.See the Polar documentation for more details on products, pricing, and webhooks.
Store your Polar credentials as Encore secrets:
$ encore secret set --type dev,local,pr,production PolarAccessToken
Locally, secrets are stored on your machine and injected when you run encore run. No .env files needed.
Create a file to configure the Polar SDK. Use Encore's secret() function to access the token. Use sandbox for development and production when deployed:
-- polar.ts --
import { Polar } from "@polar-sh/sdk";
import { secret } from "encore.dev/config";
const polarAccessToken = secret("PolarAccessToken");
const server = process.env.ENCORE_ENVIRONMENT === "production"
? "production"
: "sandbox";
export const polar = new Polar({
accessToken: polarAccessToken(),
server,
});
Use the Polar SDK to create checkout sessions for your products:
-- checkout.ts --
import { api } from "encore.dev/api";
import { polar } from "./polar";
import { getAuthData } from "~encore/auth";
interface CreateCheckoutRequest {
productId: string;
}
interface CreateCheckoutResponse {
checkoutUrl: string;
}
export const createCheckout = api(
{ auth: true, expose: true, method: "POST", path: "/checkout" },
async (req: CreateCheckoutRequest): Promise<CreateCheckoutResponse> => {
const authData = getAuthData()!;
const baseUrl = process.env.ENCORE_API_URL || "http://localhost:4000";
const session = await polar.checkouts.create({
products: [req.productId],
customerEmail: authData.email,
successUrl: `${baseUrl}/?success=true`,
});
return { checkoutUrl: session.url || "" };
}
);
Create a raw endpoint to receive webhook events from Polar:
-- webhooks.ts --
import { api } from "encore.dev/api";
import log from "encore.dev/log";
export const handleWebhook = api.raw(
{ expose: true, path: "/webhooks/polar", method: "POST" },
async (req, res) => {
const chunks: Buffer[] = [];
for await (const chunk of req) {
chunks.push(chunk);
}
const event = JSON.parse(Buffer.concat(chunks).toString());
log.info("Received Polar webhook", { type: event.type });
switch (event.type) {
case "subscription.active":
// Grant access to your product
break;
case "subscription.canceled":
// Revoke access
break;
case "order.paid":
// Fulfill the order
break;
}
res.writeHead(200);
res.end();
}
);
Register your webhook URL in the Polar dashboard under Settings > Webhooks. Use your Encore API URL followed by /webhooks/polar. Enable the events you want to handle (e.g. subscription.active, subscription.canceled, order.paid).
When you deploy, Encore automatically provisions and manages the infrastructure your app needs:
Build a Docker image and deploy anywhere:
$ encore build docker my-app:latest
See the self-hosting docs for more details.
Deploy your application to a free staging environment in Encore's development cloud:
$ git push encore main
You can also connect your own AWS or GCP account and Encore will automatically provision the infrastructure and manage secrets in your cloud. See Connect your cloud account for details.