Skill instructions
polar-integration18.1 KB
View saved version →
---
name: polar-integration
description: Add Polar billing to a TypeScript/JavaScript app using the @polar-sh/sdk package. Use this skill whenever the user wants to add a Checkout endpoint, a Customer Portal endpoint, or a Webhooks endpoint for Polar to any framework — Next.js, Express, Hono, Astro, SvelteKit, Remix, TanStack Start, Nuxt, Fastify, Elysia, Deno, Supabase Edge Functions, Cloudflare Workers, Bun, etc.
---
# Polar SDK integration
A standalone guide to wiring up Polar's three core HTTP endpoints — Checkout, Customer Portal, and Webhooks — using `@polar-sh/sdk` directly. The recipes are framework-agnostic Web Standards (`Request`/`Response`); each section also lists the small idiomatic adjustments per framework.
## Setup
Install the SDK. Version 1.0 and later needs Node.js 22 or newer:
```bash
npm install @polar-sh/sdk
# or pnpm / yarn / bun
```
If the project already uses `@polar-sh/sdk` below 1.0 (signs: `new Polar(...)`, camelCase fields such as `successUrl`, imports from `@polar-sh/sdk/webhooks`), upgrade it first by following the [migration guide](https://github.com/polarsource/polar/blob/main/sdk/typescript/.agents/skills/polar-typescript-sdk/references/migration-from-v0.md). Don't mix the old and new conventions.
Don't install the deprecated `@polar-sh/<framework>` adapters (`@polar-sh/express`, `@polar-sh/hono`, `@polar-sh/fastify`, `@polar-sh/elysia`, `@polar-sh/astro`, `@polar-sh/sveltekit`, `@polar-sh/remix`, `@polar-sh/deno`, `@polar-sh/supabase`). `@polar-sh/nextjs`, `@polar-sh/nuxt`, `@polar-sh/tanstack-start` and `@polar-sh/better-auth` are maintained; keep them if the project already uses them.
Required environment variables (use whatever loader your framework provides — `process.env`, `Deno.env`, `import.meta.env`, etc.):
- `POLAR_ACCESS_TOKEN` — organization access token. Create it with the Polar CLI (`polar auth token --scope checkouts:write --scope customer_sessions:write`, which opens a browser and prints the token, so ask the user to run it and save the output to the env file) or in the Polar dashboard (Settings → Access Tokens).
- `POLAR_WEBHOOK_SECRET` — only needed for the webhook recipe.
- `POLAR_ENVIRONMENT` — `sandbox` while developing; omit it or set `production` in production. Sandbox and production are separate, so each needs its own token.
The SDK is versioned by API version: the import path pins it. Use `2026-10`, the current version, unless the project already imports another one. Construct one client in a server-only module and reuse it:
```ts
import { createPolar, type Environment } from "@polar-sh/sdk/2026-10";
const accessToken = process.env.POLAR_ACCESS_TOKEN;
if (!accessToken) throw new Error("POLAR_ACCESS_TOKEN is required");
export const polar = createPolar({
accessToken,
environment: (process.env.POLAR_ENVIRONMENT as Environment | undefined) || "production",
});
```
The recipes below import this `polar` client. They are independent — implement only the ones the user asks for.
### Conventions
- Service and method names are camelCase (`polar.checkouts.create`, `polar.customerSessions.create`); every request and response field is `snake_case`, exactly as in the HTTP API.
- Path parameters are positional (`polar.checkouts.get(id)`), request bodies are a single object.
- Paginated lists come from `iter*` methods consumed with `for await`.
---
## Recipe 1 — Checkout endpoint
**Goal:** an HTTP endpoint that creates a Polar checkout session and 302-redirects the browser to the hosted checkout page.
**Underlying API:** `POST /v1/checkouts/` (SDK: `polar.checkouts.create(...)`). Full schema: <https://polar.sh/docs/api-reference/current/checkouts/create-checkout-session>.
### `polar.checkouts.create()` field reference
| Field | Required | Notes |
|---|---|---|
| `products` | yes | Array of product UUIDs. The first is selected by default. |
| `customer_id` | no | Existing Polar customer ID. |
| `external_customer_id` | no | Your own user ID. If no Polar customPreview of the first 4,000 characters. Read full instructions →
polar-migration8.45 KB
View saved version →
---
name: polar-migration
description: |
Guide for migrating to Polar from other payment platforms (Stripe Billing, Paddle, Lemon Squeezy). Use this skill when: (1) Planning a migration from another payment provider to Polar; (2) Moving customers, subscriptions and saved cards with Polar's Stripe migration; (3) Running both billing systems during the transition; (4) Mapping products and pricing between platforms; (5) Updating webhook and access handling for migrated subscriptions; (6) Communicating the migration to customers; (7) Testing the migration in sandbox first.
---
# Polar Migration Guide
[Polar's migration guide](https://polar.sh/docs/migrate) is the source of truth; read it before recommending anything. This skill summarizes what the application has to do.
## Pick the path
- **From Stripe:** use Polar's assisted migration under **Settings → Migrations**. Polar imports products, prices and customers, Stripe copies saved cards straight to Polar's payment processor, and Polar switches each subscription over with the same paid period. Most customers don't need to do anything. Migrations are rolling out gradually; if the tab is missing, contact [Polar support](https://polar.sh/docs/support).
- **From Paddle, Lemon Squeezy or anything else:** there's no automated migration. Contact Polar support first, then follow "Other providers" below. Customers move by checking out again on Polar.
## Rules for every migration
- Never stop, cancel or pause the old provider's billing, or activate a migrated Polar subscription, outside Polar's switch. Don't write your own cutover scripts: they double-bill.
- Never handle raw card data, and never ask for Stripe or Polar secrets in chat.
- Use the application's immutable customer ID as the Polar customer `external_id` (passed as `external_customer_id` at checkout). Not email, and not the old provider's ID unless that's already the app's canonical ID. An `external_id` can't be changed once set.
- Each subscription must have exactly one system responsible for its next renewal. Record which one, rather than inferring it from which IDs are set.
- Past payments stay in the old provider. Don't create Polar orders for transactions Polar didn't process, and keep the old account for refunds, disputes and accounting.
## From Stripe
The dashboard handles connecting Stripe, importing the catalog, copying cards and switching subscriptions. The application handles the first and last stages and the events in between.
### 1. Move new sales to Polar
Integrate Polar checkout and webhooks first (`polar-integration`), passing `external_customer_id` on every checkout. New customers then subscribe on Polar while existing subscriptions keep renewing on Stripe. Keep the Stripe IDs in your database until nothing renews there.
During coexistence, access checks must accept a valid entitlement from either provider, and cancellations or plan changes go to whichever system bills that subscription.
### 2. Map imported customers
The import creates or reuses Polar customers, but Polar can't know your application's customer IDs. Match each imported customer once on an exact, unique email, then set your ID on customers whose `external_id` is still empty. Send missing, duplicate or changed emails for review instead of guessing.
```ts
import { polar } from "./polar"; // client from polar-integration
const customer = await polar.customers.get(polarCustomerId);
if (customer.external_id === null) {
await polar.customers.update(polarCustomerId, { external_id: appCustomerId });
}
```
Imported products are new Polar products. Map each internal plan to its new Polar product and price IDs explicitly, never by name. Benefits aren't imported: attach them to the imported products before the switch if access depends on them.
### 3. Prepare for the switch
Polar stops each switched subscription on Stripe by canceling it immediately, without proration or a final invoice. Before switching:
- Turn off Stripe's canceled-sPreview of the first 4,000 characters. Read full instructions →
polar-testing13.9 KB
View saved version →
---
name: polar-testing
description: |
Guide for testing Polar payment integrations using the sandbox environment. Use this skill when: (1) Setting up the Polar sandbox for development; (2) Testing checkout flows without real payments; (3) Using Stripe test cards with Polar; (4) Writing integration tests for payment flows; (5) Testing webhooks locally with the Polar CLI (`polar webhook listen`, `polar webhook trigger`) and generating webhook fixtures; (6) Mocking Polar in unit tests; (7) Setting up CI/CD pipelines with Polar sandbox; (8) Debugging payment issues in sandbox.
---
# Polar Testing Guide
Test Polar integrations safely using the sandbox environment - a fully isolated server where you can experiment without affecting production data or processing real payments.
## Sandbox Environment
### Access
- **Dashboard**: https://sandbox.polar.sh
- **API**: https://sandbox-api.polar.sh/v1
The sandbox is completely isolated from production. You need separate:
- User account
- Organization
- Access tokens
- Webhook endpoints
### Setup Steps
1. Go to https://sandbox.polar.sh/start
2. Create a new account (or use "Go to sandbox" from org switcher)
3. Create a test organization
4. Generate an access token in Settings → Access Tokens, or with `polar auth token` once the CLI is signed in to the sandbox (see "Install and sign in" below)
### SDK Configuration
Set up the client as in `polar-integration` ("Setup") and pass `environment: "sandbox"`:
```typescript
import { createPolar } from "@polar-sh/sdk/2026-10";
const polar = createPolar({
accessToken: process.env.POLAR_ACCESS_TOKEN!,
environment: "sandbox",
});
```
```python
import os
from polar.v2026_10 import Polar
polar = Polar(os.environ["POLAR_ACCESS_TOKEN"], environment="sandbox")
```
### Sandbox Limitations
- No real money is processed, and data is isolated from production
- Customer-facing emails (receipts, renewal reminders) are only delivered to members of your organization; `you+test@example.com` aliases are accepted
- The API allows 100 requests per minute, against 500 in production, which matters for large integration suites
## Test Cards
Polar uses Stripe for payment processing, so any of [Stripe's test cards](https://docs.stripe.com/testing#cards) work. Use a future expiry date and any CVC:
| Card Number | Behavior |
|-------------|----------|
| 4242 4242 4242 4242 | Successful payment |
| 4000 0000 0000 0002 | Generic decline |
| 4000 0000 0000 9995 | Insufficient funds |
| 4000 0027 6000 3184 | Requires 3D Secure authentication |
## Local Webhook Testing
Use the Polar CLI. It forwards your organization's webhook events straight to your local server: no tunnel, no public URL, and no webhook endpoint in the dashboard.
### Install and sign in
```bash
npm install -g @polar-sh/cli
polar auth login --sandbox
```
For other install methods, see the [CLI docs](https://polar.sh/docs/integrate/cli/introduction).
`polar auth login` opens a browser, so ask the user to run it. Check the result with `polar auth whoami --json`: `environments` lists the signed-in environments and `organization` is the active one.
Where no browser is available (CI, remote machines, cloud agents), an organization access token replaces `auth login`:
```bash
export POLAR_ACCESS_TOKEN=polar_oat_... # scopes: webhooks:read, webhooks:write, organizations:read
export POLAR_ENVIRONMENT=sandbox
```
If `POLAR_ACCESS_TOKEN` is already exported in the shell, for example from the app's `.env`, the CLI uses it instead of the login.
### Forward events to your app
```bash
polar webhook listen 3000/api/polar/webhook
```
`listen` takes a port, a `port/path`, or a full URL. It runs until stopped, so start it in its own terminal or as a background process and keep it running while you test. It forwards every webhook event for the organization, including the ones real sandbox activity produces, such as completing a test checkout. If the account has several organizations, pick one witPreview of the first 4,000 characters. Read full instructions →
setup-polar7.88 KB
View saved version →
---
name: setup-polar
description: |
Interactive onboarding wizard to set up Polar payment integration from scratch. Use this skill when: (1) User wants to "set up Polar" or "integrate Polar" in their project; (2) User is starting fresh with Polar and needs guided setup; (3) User asks "how do I get started with Polar"; (4) User wants to add payments/subscriptions/checkout to their app using Polar; (5) User needs help creating their first Polar product and checkout. This skill walks through MCP installation, authentication, product creation, and generates framework-specific integration code.
---
# Polar Setup Wizard
Interactive setup guide to get Polar payments working in your project.
## Setup Flow
Follow these steps in order:
### Step 1: Check MCP Availability
First, check if the Polar MCP server is available by listing organizations: call `execute` with `GET /v1/organizations/`, or `organizations_list` where the server exposes one tool per operation.
**If MCP tools work:** Skip to Step 3.
**If MCP not available:** Continue to Step 2.
### Step 2: Install Polar MCP
**Polar plugin installed:** the plugin already configures the Polar server (`polar`, plus `polar-sandbox` where available). Ask the user to sign in to it, preferring `polar-sandbox`: in Claude Code with `/mcp`, in Codex with `codex mcp login <server>`, in Cursor or Antigravity from their MCP settings, in Gemini CLI with `/mcp auth <server>`, and in ChatGPT when prompted to connect. Then continue with the verification below.
Otherwise, guide the user to install the Polar MCP server based on their environment:
**Claude Code:**
```bash
# Production
claude mcp add --transport http polar https://mcp.polar.sh/mcp/polar-mcp
# Sandbox (recommended for setup)
claude mcp add --transport http polar-sandbox https://mcp.polar.sh/mcp/polar-sandbox
```
**Cursor** (`.cursor/mcp.json`):
```json
{
"mcpServers": {
"polar-sandbox": {
"url": "https://mcp.polar.sh/mcp/polar-sandbox"
}
}
}
```
For other clients, follow the [Polar MCP guide](https://polar.sh/docs/integrate/mcp). After installing, the user restarts their editor or CLI and signs in when prompted (in Claude Code, run `/mcp` and authenticate). The sandbox server signs in at sandbox.polar.sh and the production server at polar.sh.
Once authenticated, verify MCP works by listing organizations.
### Step 3: Gather Project Context
Ask the user:
1. **Framework**: What framework are you using?
- Next.js (App Router), Express, Hono, Astro, SvelteKit, Remix, TanStack Start, Nuxt, Fastify, Cloudflare Workers, or another TypeScript/JavaScript framework
- Python: there's no integration skill; follow the [Python SDK docs](https://polar.sh/docs/integrate/sdk/python)
2. **Environment**: Start with sandbox or production?
- Sandbox (recommended for new setups)
- Production
3. **Product type**: What are you selling?
- Subscription (recurring)
- One-time purchase
- Both
From here on, use the `polar-sandbox` server's tools for sandbox and the `polar` server's tools for production. If only `polar` is available (as in ChatGPT), create sandbox products in the sandbox dashboard or with the Polar CLI instead.
### Step 4: Choose the Organization
List the organizations with MCP. If there are several, ask which one to use. Note its `id`, `slug` and `default_presentment_currency`. Signing in to the MCP server already asks a user without an organization to create one; without MCP, they can create one at:
- Sandbox: https://sandbox.polar.sh/start
- Production: https://polar.sh/start
### Step 5: Create First Product
Create the product with MCP (`POST /v1/products/`). The price must be in the organization's `default_presentment_currency`, and the billing interval is fixed per product. Example for a monthly subscription:
```json
{
"organization_id": "<organization id from Step 4>",
"name": "Pro Plan",
"recurring_interval": "month",
"prices": [{ "amount_type": "fixed", "price_amount": 29Preview of the first 4,000 characters. Read full instructions →