> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kavachos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Polar payments

> Wire Polar subscription billing into KavachOS with the `polar()` plugin. Set an access token and webhook secret to sync checkout and subscription state.

Polar is an open-source funding platform for developers. The KavachOS plugin wires Polar checkout sessions and subscription webhooks to your user records, no Polar SDK required.

## Setup

<Steps>
  <Step>
    ### Get your credentials

    From your [Polar dashboard](https://polar.sh), go to **Settings → API** and create an access token. Under **Webhooks**, create an endpoint pointing to `/api/kavach/auth/polar/webhook` and copy the signing secret.
  </Step>

  <Step>
    ### Configure the plugin

    ```ts theme={"system"}
    import { createKavach } from 'kavachos';
    import { polar } from 'kavachos/auth';

    const kavach = await createKavach({
      database: { provider: 'postgres', url: process.env.DATABASE_URL },
      plugins: [
        polar({
          accessToken: process.env.POLAR_ACCESS_TOKEN,
          webhookSecret: process.env.POLAR_WEBHOOK_SECRET,
          sandbox: process.env.NODE_ENV !== 'production',
          onSubscriptionChange: async (userId, sub) => {
            console.log(`User ${userId}: ${sub.status}`);
          },
        }),
      ],
    });
    ```
  </Step>
</Steps>

## Usage

### Create a checkout session

```ts theme={"system"}
// From an authenticated endpoint
const { url } = await kavach.plugins.polar.createCheckout(userId, 'product_xxx', {
  successUrl: 'https://example.com/success',
});

// Redirect the user
redirect(url);
```

### Check subscription status

```ts theme={"system"}
const sub = await kavach.plugins.polar.getSubscription(userId);

if (sub?.status === 'active') {
  // grant access
}
```

## HTTP endpoints

The plugin registers three routes under your KavachOS base path.

### POST /auth/polar/checkout

Creates a checkout session. Requires an authenticated session.

```json theme={"system"}
// Request body
{ "productId": "product_xxx", "successUrl": "https://example.com/success" }

// Response
{ "url": "https://buy.polar.sh/...", "id": "checkout_xxx" }
```

### GET /auth/polar/subscription

Returns the current subscription for the authenticated user.

```json theme={"system"}
{
  "subscription": {
    "id": "sub_xxx",
    "status": "active",
    "productId": "product_xxx",
    "currentPeriodEnd": "2025-12-31T00:00:00.000Z",
    "cancelAtPeriodEnd": false
  }
}
```

Returns `{ "subscription": null }` when the user has no active subscription.

### POST /auth/polar/webhook

Receives webhook events from Polar. Signature is verified with HMAC-SHA256, no session auth needed.

Handled events:

| Event                  | Action                              |
| ---------------------- | ----------------------------------- |
| `subscription.created` | Links customer, stores subscription |
| `subscription.updated` | Updates status and period end       |
| `subscription.revoked` | Clears subscription, fires callback |

## Sandbox mode

Set `sandbox: true` to point at `sandbox.api.polar.sh` during development. Polar's sandbox environment mirrors the production API and lets you test webhooks without real payments.

```ts theme={"system"}
polar({
  accessToken: process.env.POLAR_SANDBOX_TOKEN,
  webhookSecret: process.env.POLAR_SANDBOX_WEBHOOK_SECRET,
  sandbox: true,
})
```

## Reference

### `PolarConfig`

| Field                  | Type        | Description                                  |
| ---------------------- | ----------- | -------------------------------------------- |
| `accessToken`          | `string`    | Polar API access token                       |
| `webhookSecret`        | `string`    | Webhook signing secret for HMAC verification |
| `organizationId`       | `string?`   | Scope checkouts to a specific organization   |
| `sandbox`              | `boolean?`  | Use sandbox environment (default: `false`)   |
| `onSubscriptionChange` | `function?` | Called whenever subscription status changes  |

### `PolarSubscription`

| Field               | Type      | Description                                        |
| ------------------- | --------- | -------------------------------------------------- |
| `id`                | `string`  | Polar subscription ID                              |
| `status`            | `string`  | `active`, `canceled`, `trialing`, `past_due`, etc. |
| `productId`         | `string`  | Polar product ID                                   |
| `currentPeriodEnd`  | `Date`    | When the current billing period ends               |
| `cancelAtPeriodEnd` | `boolean` | Whether cancellation is scheduled                  |

<Info>
  KavachOS stores Polar subscription data in the `kavach_users` table. You can query it directly with Drizzle or any SQL client.
</Info>
