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

# Webhooks Overview

> Polar webhook integration for subscription management

<Warning>
  **Internal Documentation Only:** If you're not a Null Tools developer, you can close this documentation or visit the [Apps section](/apps/coming-soon) to learn more about using Null Pass in your applications.
</Warning>

## Overview

Null Pass integrates with Polar.sh for subscription management. Webhooks from Polar are received and processed to update user service entitlements automatically.

## Supported Webhooks

<CardGroup cols={2}>
  <Card title="DROP Webhooks" icon="cloud-arrow-up" href="/api-reference/webhooks/drop">
    `/api/webhooks/drop`
  </Card>

  <Card title="MAILS Webhooks" icon="envelope" href="/api-reference/webhooks/mails">
    `/api/webhooks/mails`
  </Card>

  <Card title="VAULT Webhooks" icon="lock" href="/api-reference/webhooks/vault">
    `/api/webhooks/vault`
  </Card>

  <Card title="DB Webhooks" icon="database" href="/api-reference/webhooks/db">
    `/api/webhooks/db`
  </Card>
</CardGroup>

## Webhook Endpoints

Each service has its own webhook endpoint:

* `POST /api/webhooks/drop`
* `POST /api/webhooks/mails`
* `POST /api/webhooks/vault`
* `POST /api/webhooks/db`

## Webhook Processing

All webhooks are processed by `handlePolarWebhook()` in `lib/webhook-handlers.ts`. The handler:

1. Sends Discord notification (if configured)
2. Processes webhook based on event type
3. Updates user entitlements
4. Creates audit log entries
5. Handles errors gracefully

## Supported Events

<ResponseField name="checkout.updated" type="event">
  Checkout status update
</ResponseField>

<ResponseField name="subscription.created" type="event">
  New subscription created

  * Updates user entitlement
  * Sets premium status if active
  * Sends payment success notification
  * Creates audit log
</ResponseField>

<ResponseField name="subscription.updated" type="event">
  Subscription updated

  * Updates entitlement with new status
  * Adjusts premium flag
  * Creates audit log
</ResponseField>

<ResponseField name="subscription.active" type="event">
  Subscription activated

  * Same as subscription.updated
</ResponseField>

<ResponseField name="subscription.canceled" type="event">
  Subscription canceled

  * Marks subscription as canceled
  * Access continues until period end
  * Creates audit log
</ResponseField>

<ResponseField name="subscription.revoked" type="event">
  Subscription revoked

  * Immediately removes premium access
  * Resets to free tier
  * Creates audit log
</ResponseField>

<ResponseField name="customer.created" type="event">
  Customer created

  * Links Polar customer ID to user
  * Creates entitlement if needed
</ResponseField>

<ResponseField name="customer.updated" type="event">
  Customer updated

  * Updates Polar customer ID
</ResponseField>

<ResponseField name="customer.deleted" type="event">
  Customer deleted

  * Removes Polar customer link
  * Resets to free tier
</ResponseField>

## Webhook Security

Webhooks are secured using Polar's webhook secret verification:

<ResponseField name="DROP_POLAR_SECRET" type="string" required>
  Webhook secret for DROP service
</ResponseField>

<ResponseField name="MAILS_POLAR_SECRET" type="string" required>
  Webhook secret for MAILS service
</ResponseField>

<ResponseField name="VAULT_POLAR_SECRET" type="string" required>
  Webhook secret for VAULT service
</ResponseField>

<ResponseField name="DB_POLAR_SECRET" type="string" required>
  Webhook secret for DB service
</ResponseField>

## Implementation

### Code Reference

```4:10:nullpass_clean/src/app/api/webhooks/drop/route.ts theme={null}
export const POST = Webhooks({
  webhookSecret: process.env.DROP_POLAR_SECRET!,
  
  onPayload: async (payload) => {
    await handlePolarWebhook(payload, 'DROP')
  },
})
```

## User Identification

Webhooks identify users through:

1. `metadata.userId` in subscription/customer object (preferred)
2. Customer email lookup if userId not present

## Subscription Status Mapping

* **active** → `isPremium: true`, tier set from metadata
* **canceled** → Status marked as canceled, access continues
* **revoked** → `isPremium: false`, tier reset to "free"

## Audit Events

Webhooks create the following audit log entries:

* `SUBSCRIPTION_CREATE`
* `SUBSCRIPTION_UPDATE`
* `SUBSCRIPTION_CANCEL`
* `SUBSCRIPTION_REVOKE`

## Error Handling

* Errors are logged but don't fail the webhook
* Discord notifications failures don't block processing
* Database errors are caught and logged
* Webhook processing continues even if individual steps fail
