---
title: Polar
description: Sell the catalog through Polar as merchant of record, with products and meters the deploy creates.
---

Polar sells as merchant of record: it calculates and collects tax, hosts the
checkout and keeps the subscription. Paykit creates the products and meters the
catalog states and records what Polar collects.

## Deploy the vendor objects

`PolarBilling` creates a product per sold plan and a meter per metered feature.
It returns the provider the billing stack validates, plus the ids the Worker
needs:

```ts title="alchemy.run.ts"
import { PolarBilling, polarProviders } from "@potion.run/paykit-polar";
import * as Layer from "effect/Layer";

const providers = Layer.mergeAll(Cloudflare.providers(), Paykit.providers()).pipe(
  Layer.provideMerge(polarProviders({ server: "sandbox" })),
);

const billing = yield* PolarBilling("PolarBilling", {
  server: "sandbox",
  origin: "https://app.example.com",
  tiers: polarTiers,
});

const recorded = yield* Paykit.BillingStack("Billing", {
  catalog: billingCatalog,
  providers: [billing],
});
```

The deploy's token comes from `POLAR_API_KEY`, or from the profile
`ALCHEMY_PROFILE` selects (`alchemy profile edit --provider Polar`). Nothing is
copied into the stack, and `server: "sandbox"` pins the base URL so a
production token cannot create production objects.

`polarTiers` repeats the catalog's prices in the shape Polar sells them:
`{ pro: { price: proPrice, usage: { messages: messagePrice } } }`.

`billing.sold` carries the ids: `sold.products.pro` and `sold.meters.messages`.
`billing.accessToken` is the token the deploy resolved; bind it with the ids
into the Worker's environment as `POLAR_API_KEY`.

`billing.webhookEndpoint` is the endpoint the deploy created: `resource` is the
vendor object, and `secret` is the signing key Polar minted at create. Bind the
secret into the Worker's environment — Polar never returns it again, so the
endpoint's state is the only copy:

```ts title="alchemy.run.ts"
const worker = yield* Cloudflare.Worker("Worker", {
  main: "./src/Worker.ts",
  env: {
    POLAR_API_KEY: billing.accessToken,
    POLAR_WEBHOOK_SECRET: billing.webhookEndpoint.secret,
  },
});
```

## Build the runtime provider

The runtime provider takes the product id and the meter name from the
environment:

```ts title="src/billing.ts"
import { Polar } from "@potion.run/paykit-polar";
import * as Redacted from "effect/Redacted";

export const provider = Polar({
  accessToken: env.POLAR_API_KEY,
  server: "sandbox",
  origin: "https://app.example.com",
  tiers: {
    pro: {
      price: proPrice,
      productId: env.POLAR_PRODUCT_PRO,
      usage: { messages: messagePrice },
    },
  },
  meters: { messages: env.POLAR_MESSAGES_METER },
  webhookSecret: Redacted.make(env.POLAR_WEBHOOK_SECRET),
});
```

The example pins `server: "sandbox"`, so a production token cannot create
production objects from it. A live deployment states its own server.

## Deliveries

`PolarBilling` creates the endpoint at `${origin}/webhooks/polar` —
`webhookPath` moves it — and subscribes it to exactly the events the provider
decodes, so the vendor's event list cannot drift from what paykit handles. A
delivery is verified with the secret the endpoint minted, decoded by the
provider, and applied as a command. The account becomes active on the delivery,
not on the redirect from checkout.

Destroying the stack deletes the endpoint: it is configuration, not financial
history, and a retired deployment must stop receiving deliveries. A deployment
that already owns one — a shared API, a secret in a vault — passes
`webhookSecret` instead, and nothing is created.

`client` is for a test only. A deployment omits it, and Polar builds its own
client from the token.

See [Credits](/concepts/credits) for a plan that grants a pool, and
[the Polar example](https://github.com/potion-run/paykit/tree/main/examples/polar)
for the whole loop: a deploy, a checkout, a signed delivery and a test that needs
no Polar account.

The pages are [Polar](/reference/paykit-polar/polar), [PolarBilling](/reference/paykit-polar/polar-billing), and [PolarPrices](/reference/paykit-polar/polar-prices).
