@polar-sh/nuxt

Polar.sh integration for Nuxt
23,168 10,397
Install
npm install @polar-sh/nuxt
Latest Version:1.1.0
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm
Maintainer: birkjernstrom

@polar-sh/nuxt

Payments and Checkouts made dead simple with Nuxt.

Installation

Install the package

Choose your preferred package manager to install the module:

pnpm add @polar-sh/nuxt zod

The module requires Nuxt 4 and Node.js 22 or later.

Register the module

Add the module to your nuxt.config.ts, along with the runtime config the handlers below read from:

export default defineNuxtConfig({
  modules: ['@polar-sh/nuxt'],
  runtimeConfig: {
    private: {
      polarAccessToken: '', // NUXT_PRIVATE_POLAR_ACCESS_TOKEN
      polarServer: '', // NUXT_PRIVATE_POLAR_SERVER - "sandbox" or "production"
      polarCheckoutSuccessUrl: '', // NUXT_PRIVATE_POLAR_CHECKOUT_SUCCESS_URL
      polarWebhookSecret: '', // NUXT_PRIVATE_POLAR_WEBHOOK_SECRET
    },
  },
})

The module auto-imports Checkout, CustomerPortal and Webhooks in your server/ code.

Checkout

Create a Checkout handler which takes care of redirections.

// server/routes/api/checkout.get.ts
export default defineEventHandler((event) => {
  const {
    private: { polarAccessToken, polarCheckoutSuccessUrl, polarServer },
  } = useRuntimeConfig()

  const checkoutHandler = Checkout({
    accessToken: polarAccessToken,
    successUrl: polarCheckoutSuccessUrl,
    returnUrl: 'https://myapp.com', // Optional Return URL, which renders a Back-button in the Checkout
    environment: polarServer as 'sandbox' | 'production',
    theme: 'dark', // Enforces the theme - System-preferred theme will be set if left omitted
  })

  return checkoutHandler(event)
})

Query Params

Pass query params to this route.

  • products ?products=123 - Separate multiple products with commas: ?products=123,456
  • customer_id (optional) ?products=123&customer_id=xxx
  • external_customer_id (optional) ?products=123&external_customer_id=xxx
  • customer_email (optional) ?products=123&customer_email=janedoe@gmail.com
  • customer_name (optional) ?products=123&customer_name=Jane
  • discount_code (optional) ?products=123&discount_code=SAVE20 - Apply a discount code before redirecting. Discount codes must be enabled; discount_id takes precedence when both are supplied.
  • seats (optional) ?products=123&seats=5 - Number of seats for seat-based products
  • metadata (optional) URL-Encoded JSON string

Customer IP Address

Unless customer_ip_address is passed, the customer's IP address is taken from the x-forwarded-for, x-real-ip or cf-connecting-ip header and sent to Polar to show local currency. Set customerIpAddress to a function (request) => ip to resolve it yourself, or to false to not send it.

Customer Portal

Create a customer portal where your customer can view orders and subscriptions.

// server/routes/api/portal.get.ts
export default defineEventHandler((event) => {
  const {
    private: { polarAccessToken, polarServer },
  } = useRuntimeConfig()

  const customerPortalHandler = CustomerPortal({
    accessToken: polarAccessToken,
    environment: polarServer as 'sandbox' | 'production',
    getCustomerId: (event) => {
      // Use your own logic to get the Polar customer ID - from a database, session, etc.
      return Promise.resolve('9d89909b-216d-475e-8005-053dba7cff07')
    },
    returnUrl: 'https://myapp.com', // Optional Return URL, which renders a Back-button in the Customer Portal
  })

  return customerPortalHandler(event)
})

Webhooks

A simple utility which resolves incoming webhook payloads by verifying their signature with your webhook secret.

// server/routes/webhook/polar.post.ts
export default defineEventHandler((event) => {
  const {
    private: { polarWebhookSecret },
  } = useRuntimeConfig()

  const webhooksHandler = Webhooks({
    webhookSecret: polarWebhookSecret,
    onPayload: async (payload) => {
      // Handle the payload
      // No need to return an acknowledge response
    },
  })

  return webhooksHandler(event)
})

Payload Handlers

The Webhook handler also supports granular handlers for easy integration.

  • onPayload: (payload) => - Called for every event, in addition to the matching handler below
  • onCheckoutCreated: (payload) =>
  • onCheckoutExpired: (payload) =>
  • onCheckoutUpdated: (payload) =>
  • onOrderCreated: (payload) =>
  • onOrderUpdated: (payload) =>
  • onOrderPaid: (payload) =>
  • onOrderRefunded: (payload) =>
  • onRefundCreated: (payload) =>
  • onRefundUpdated: (payload) =>
  • onSubscriptionCreated: (payload) =>
  • onSubscriptionUpdated: (payload) =>
  • onSubscriptionActive: (payload) =>
  • onSubscriptionCanceled: (payload) =>
  • onSubscriptionCycled: (payload) =>
  • onSubscriptionPastDue: (payload) =>
  • onSubscriptionPaused: (payload) =>
  • onSubscriptionResumed: (payload) =>
  • onSubscriptionRevoked: (payload) =>
  • onSubscriptionUncanceled: (payload) =>
  • onProductCreated: (payload) =>
  • onProductUpdated: (payload) =>
  • onOrganizationUpdated: (payload) =>
  • onBenefitCreated: (payload) =>
  • onBenefitUpdated: (payload) =>
  • onBenefitGrantCreated: (payload) =>
  • onBenefitGrantCycled: (payload) =>
  • onBenefitGrantUpdated: (payload) =>
  • onBenefitGrantRevoked: (payload) =>
  • onCustomerCreated: (payload) =>
  • onCustomerUpdated: (payload) =>
  • onCustomerDeleted: (payload) =>
  • onCustomerStateChanged: (payload) =>
  • onCustomerSeatAssigned: (payload) =>
  • onCustomerSeatClaimed: (payload) =>
  • onCustomerSeatRevoked: (payload) =>
  • onDiscountCreated: (payload) =>
  • onDiscountUpdated: (payload) =>
  • onDiscountDeleted: (payload) =>
  • onMemberCreated: (payload) =>
  • onMemberUpdated: (payload) =>
  • onMemberDeleted: (payload) =>

Handlers are async functions. Webhook payloads use the generated SDK's snake_case fields. Signed events unknown to the installed SDK version are acknowledged and ignored so newly introduced event types do not cause retries.

Version History

Version Released License
1.1.0 MIT
1.0.1 MIT
1.0.0 MIT
0.5.7 MIT
0.5.6 MIT