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

# Billing & Webhooks

> Manage subscriptions, checkout sessions, usage, and Polar webhooks.

<style>
  {`
      main, article, .prose {
        margin-left: 2.5cm !important;
        margin-right: 2.5cm !important;
      }
      `}
</style>

Administrative endpoints to manage billing subscriptions, quotas, checkout processes, and handle incoming payment notifications from Polar.

<Warning>
  **Session JWT Required**

  All billing routes except the webhook require the user's WorkOS AuthKit session JWT. Webhooks use cryptographic signature verification.
</Warning>

***

## 1. Create Checkout Session

Create a checkout session for Polar plan subscriptions (e.g. Pro or Team).

```http theme={null}
POST /billing/create-checkout
```

**Request Body**

```json theme={null}
{ "productId": "polar_prod_12345", "successUrl": "https://sovseal.com/success" }
```

**Response (200 OK)**

```json theme={null}
{ "url": "https://sandbox.polar.sh/checkout/12345" }
```

***

## 2. Customer Portal Link

Retrieve a redirect link to the Polar customer billing portal.

```http theme={null}
POST /billing/customer-portal
```

**Request Body**

```json theme={null}
{ "returnUrl": "https://app.sovseal.com/plan" }
```

***

## 3. Retrieve Subscription

Fetch current plan configurations and quota states for the user.

```http theme={null}
GET /billing/subscription
```

**Response (200 OK)**

```json theme={null}
{
  "subscription": {
    "user_id": "0x123456789...",
    "plan": "pro",
    "status": "active",
    "quota_sync_ops": 9007199254740991,
    "quota_storage_bytes": 10736349806592,
    "quota_subkeys": 9007199254740991,
    "quota_devices": 50,
    "seat_count": 3,
    "included_seats": 3,
    "polar_customer_id": "cust_123",
    "polar_subscription_id": "sub_456",
    "current_period_end": "2026-07-09T16:45:30Z"
  }
}
```

<Note>
  `quota_sync_ops`, `quota_storage_bytes`, and `quota_subkeys` are not currently enforced as differentiators — every plan carries an effectively unlimited value for these three. The quotas that actually vary by plan are `quota_devices` (3 on Hobby, up to unlimited on Enterprise) and seats (`seat_count` / `included_seats`, Growth and Pro plans only — see [Update Seats](#6-update-seats)).
</Note>

***

## 4. Retrieve Usage Metrics

Retrieve cumulative usage statistics across all of the user's API keys for the current billing cycle.

```http theme={null}
GET /billing/usage
```

**Response (200 OK)**

```json theme={null}
{
  "usage": {
    "sync_ops": 4252,
    "store_ops": 4252,
    "recall_requests": 14205,
    "bytes_stored": 4582103,
    "devices": 3
  }
}
```

***

## 5. Polar Webhook Handler

Receives cryptographically signed webhook calls from Polar to update user subscriptions on the fly.

```http theme={null}
POST /billing/webhook
```

* **Security**: Signature verification using Standard Webhooks HMAC. Rejects missing or invalid signatures with `403 invalid_webhook_signature`.
* **Events Handled**:
  * `subscription.created` / `subscription.active` — Upsert active plan and reset quotas.
  * `subscription.updated` — Sync period boundaries and subscription statuses.
  * `subscription.canceled` / `subscription.revoked` — Reset status to canceled, drop quotas back to the Free plan.

***

## 6. Update Seats

Change the seat count on a team subscription. Growth, Pro, and Enterprise plans only — the request is rejected on any other plan.

```http theme={null}
POST /billing/update-seats
```

**Request Body**

```json theme={null}
{ "seats": 5 }
```

* Looks up the caller's Polar subscription and rejects with `404 no_polar_subscription` if none exists.
* Rejects with `403 plan_does_not_support_seats` unless the plan is `growth`, `pro`, or `enterprise`.
* Calls Polar's subscription update API with `prorationBehavior: "invoice"`, then mirrors the new `seat_count` into the local `subscriptions` row for immediate UI feedback.

**Response (200 OK)**

```json theme={null}
{ "success": true }
```
