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

# Nuxt 适配器

> 将 Dodo Payments checkout、Customer Portal 和 webhook server routes 添加到 Nuxt 3 应用中，使用 @dodopayments/nuxt module 和 runtime config。

`@dodopayments/nuxt` module 为 Nuxt 应用提供三个 server route handlers。`checkoutHandler` 返回 checkout URLs，`customerPortalHandler` 将客户发送到 Customer Portal，而 `Webhooks` 验证 webhook events 并将其路由到你的代码。

> **[Checkout API Route](#checkout-route-handler)**
>
> 从 Nuxt server route 创建 checkout URLs。

> **[Customer Portal API Route](#customer-portal-route-handler)**
>
> 让客户通过 Nuxt server route 管理其订阅和详细信息。

> **[Webhooks API Route](#webhook-route-handler)**
>
> 在 Nuxt 中接收并验证 Dodo Payments webhook events。

## 概述

> [!NOTE]
>
> 该 module 将其 handlers 注册为 Nuxt server auto-imports，因此你的 server routes 无需 import statements 即可调用 `checkoutHandler`、`customerPortalHandler` 和 `Webhooks`。每个 route 都从 `runtimeConfig` 读取 credentials。Nuxt 只向浏览器公开 `runtimeConfig.public`，因此 API key 和 webhook secret 会保留在 server 上。

## 安装

**1. Install the Nuxt Module**

在项目根目录运行此命令：

```bash theme={null}
npm install @dodopayments/nuxt
```

该 module 将 Nuxt 3（3.13.1 或更高版本）和 `zod` 3.25 或更高版本列为 peer dependencies。

**2. Register the Module in nuxt.config.ts**

将 `@dodopayments/nuxt` 添加到 `modules` 数组，并将 credentials 映射到 `runtimeConfig`：

```typescript nuxt.config.ts expandable theme={null}
export default defineNuxtConfig({
  modules: ["@dodopayments/nuxt"],
  devtools: { enabled: true },
  compatibilityDate: "2025-02-25",
  runtimeConfig: {
    private: {
      bearerToken: process.env.NUXT_PRIVATE_BEARER_TOKEN,
      webhookKey: process.env.NUXT_PRIVATE_WEBHOOK_KEY,
      environment: process.env.NUXT_PRIVATE_ENVIRONMENT,
      returnUrl: process.env.NUXT_PRIVATE_RETURN_URL
    },
  }
});
```

设置这些 environment variables，例如在项目根目录的 `.env` 文件中设置：

| Variable | Value |
| - | - |
| `NUXT_PRIVATE_BEARER_TOKEN` | 你的 API key。在 dashboard 的 **Developer → API Keys** 下创建。 |
| `NUXT_PRIVATE_WEBHOOK_KEY` | 你的 webhook secret。在 **Developer → Webhooks** 下添加 endpoint，并复制其 signing secret。 |
| `NUXT_PRIVATE_ENVIRONMENT` | `test_mode` 或 `live_mode`。如果未设置，handlers 将使用 `live_mode`。 |
| `NUXT_PRIVATE_RETURN_URL` | 可选。checkout 后客户跳转到的 URL。 |

构建后的 Nuxt server 不会读取你的 `.env` 文件。在 runtime 中，Nuxt 只会根据与其路径匹配的 variable 覆盖 `runtimeConfig` 值，例如 `private.returnUrl` 对应的 `NUXT_PRIVATE_RETURN_URL`，因此也要在 hosting environment 中设置这些 variables。

> [!WARNING]
>
> 切勿将 `.env` 文件或 secrets 提交到 version control。

## API Route Handler 示例

> [!NOTE]
>
> 这些示例会在 `server/routes/api/` directory 中创建 server routes。Nuxt 根据文件名和 method suffix 为每个文件创建 route，因此 `checkout.get.ts` 会处理 `GET /api/checkout`。

**Checkout API Route**

> [!NOTE]
>
> 使用此 handler 将 Dodo Payments checkout 添加到 Nuxt 应用。GET route 提供 static checkout。POST route 提供 checkout sessions；设置 `type: "dynamic"` 后，也可提供 dynamic checkout。

为 static checkout 创建 GET route：

```typescript server/routes/api/checkout.get.ts expandable theme={null}
export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment, returnUrl },
  } = useRuntimeConfig();

  const handler = checkoutHandler({
    bearerToken: bearerToken,
    environment: environment as "test_mode" | "live_mode",
    returnUrl: returnUrl,
  });

  return handler(event);
});
```

`checkout.post.ts` 提供一个 POST flow。使用 dynamic checkout 示例或 checkout session 示例之一：

```typescript server/routes/api/checkout.post.ts expandable theme={null}
export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment, returnUrl },
  } = useRuntimeConfig();

  const handler = checkoutHandler({
    bearerToken: bearerToken,
    environment: environment as "test_mode" | "live_mode",
    returnUrl: returnUrl,
    type: "dynamic"
  });

  return handler(event);
});
```

```typescript server/routes/api/checkout.post.ts (Checkout Sessions) expandable theme={null}
export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment, returnUrl },
  } = useRuntimeConfig();

  const handler = checkoutHandler({
    bearerToken: bearerToken,
    environment: environment as "test_mode" | "live_mode",
    returnUrl: returnUrl,
    type: "session"
  });

  return handler(event);
});
```

> [!WARNING]
>
> 如果 `productId` 缺失或无效，handler 将返回 400 response。

要测试这些 routes，请发送以下 requests：

```bash Static Checkout cURL Example theme={null}
curl --request GET \
--url 'https://example.com/api/checkout?productId=pdt_fqJhl7pxKWiLhwQR042rh'
```

```bash Dynamic Checkout cURL Example expandable theme={null}
curl --request POST \
--url https://example.com/api/checkout \
--header 'Content-Type: application/json' \
--data '{
"billing": {
  "city": "Austin",
  "country": "US",
  "state": "TX",
  "street": "123 Main St",
  "zipcode": "78701"
},
"customer": {
  "email": "customer@example.com",
  "name": "John Doe"
},
"metadata": {},
"payment_link": true,
"product_id": "pdt_QMDuvLkbVzCRWRQjLNcs",
"quantity": 1,
"billing_currency": "USD",
"discount_codes": ["IKHZ23M9GQ"],
"return_url": "https://example.com",
"trial_period_days": 10
}'
```

```bash Checkout Session cURL Example expandable theme={null}
curl --request POST \
--url https://example.com/api/checkout \
--header 'Content-Type: application/json' \
--data '{
"product_cart": [
  {
    "product_id": "pdt_QMDuvLkbVzCRWRQjLNcs",
    "quantity": 1
  }
],
"customer": {
  "email": "customer@example.com",
  "name": "John Doe"
},
"return_url": "https://example.com/success"
}'
```

**Customer Portal API Route**

> [!NOTE]
>
> 创建一个 GET route，将客户发送到其 Customer Portal。该 route 从 query string 读取 `customer_id`。

```typescript server/routes/api/customer-portal.get.ts expandable theme={null}
export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment },
  } = useRuntimeConfig();

  const handler = customerPortalHandler({
    bearerToken,
    environment: environment as "test_mode" | "live_mode",
  });

  return handler(event);
});
```

**Query Parameters：**

* `customer_id`（必需）：portal session 的 customer ID，例如 `?customer_id=cus_123`。
* `send_email`（可选，boolean）：如果为 `true`，Dodo Payments 还会将 portal link 发送到客户的 email。

> [!WARNING]
>
> 从 `@dodopayments/nuxt` 0.2.11 开始，如果缺少 `customer_id`，handler 将返回 HTTP `400`；如果无法创建 portal session，则返回 HTTP `500`。在此之前的版本在这两种情况下都会返回 HTTP `200`，并附带类似 `{ "status": 400, "body": "Missing customer_id in query parameters" }` 的 JSON body。若要依赖 HTTP status，请升级到 0.2.11 或更高版本。

```bash Customer Portal cURL Example theme={null}
curl --request GET \
--url 'https://example.com/api/customer-portal?customer_id=cus_9VuW4K7O3GHwasENg31m&send_email=true'
```

**Webhook API Route**

> [!NOTE]
>
> 创建一个 POST route 来接收 Dodo Payments webhook events 并验证其 signatures。

```typescript server/routes/api/webhook.post.ts expandable theme={null}
export default defineEventHandler((event) => {
  const {
    private: { webhookKey },
  } = useRuntimeConfig();

  const handler = Webhooks({
    webhookKey: webhookKey,
    onPayload: async (payload: any) => {
      // Handle webhook payload here
    },
    // ...add other event handlers as needed
  });

  return handler(event);
});
```

## Checkout Route Handler

checkout handler 支持使用 Dodo Payments 收款的三种方式：

* **Static Payment Links：** 可分享的 URLs，无需代码即可收款。
* **Dynamic Payment Links：** 使用自定义详细信息生成的 payment links。它们使用 deprecated endpoints。
* **Checkout Sessions：** 托管式 checkout，支持 product cart、customer details 和 customization options。这是推荐的 flow。

`checkoutHandler` 接受以下 options：

| Option | Type | Description |
| - | - | - |
| `bearerToken` | `string` | 你的 Dodo Payments API key。 |
| `environment` | `string` | `test_mode` 或 `live_mode`。默认为 `live_mode`。 |
| `returnUrl` | `string` | 可选。checkout 在 payment 后将客户重定向到的 URL。POST body 中的 `return_url` 优先级更高。 |
| `type` | `string` | 可选。在 GET route 中，将其留空或设置为 `static`，因为其他值会使 static checkout 返回 400。在 POST route 中，`dynamic` 选择 dynamic checkout，任何其他值或不设置则选择 checkout sessions。 |

> **Static Checkout (GET)**
>
> ### 支持的 Query Parameters
>
> **productId** `string` *required*
>
> Product identifier，例如 `?productId=pdt_nZuwz45WAs64n3l07zpQR`。
>
> **quantity** `integer` (default: 1)
>
> Product 的数量。
>
> **fullName** `string`
>
> Customer 的全名。如果提供了 `firstName` 或 `lastName`，则忽略此项。
>
> **firstName** `string`
>
> Customer 的名字。
>
> **lastName** `string`
>
> Customer 的姓氏。
>
> **email** `string`
>
> Customer 的 email address。
>
> **country** `string`
>
> Customer 的国家，以 ISO 3166-1 alpha-2 code 表示。
>
> **addressLine** `string`
>
> Customer 的 address line。
>
> **city** `string`
>
> Customer 的 city。
>
> **state** `string`
>
> Customer 的 state 或 province。
>
> **zipCode** `string`
>
> Customer 的 ZIP 或 postal code。
>
> **disableFullName** `boolean`
>
> 设置为 `true` 可禁用 full name field。
>
> **disableFirstName** `boolean`
>
> 设置为 `true` 可禁用 first name field。
>
> **disableLastName** `boolean`
>
> 设置为 `true` 可禁用 last name field。
>
> **disableEmail** `boolean`
>
> 设置为 `true` 可禁用 email field。
>
> **disableCountry** `boolean`
>
> 设置为 `true` 可禁用 country field。
>
> **disableAddressLine** `boolean`
>
> 设置为 `true` 可禁用 address line field。
>
> **disableCity** `boolean`
>
> 设置为 `true` 可禁用 city field。
>
> **disableState** `boolean`
>
> 设置为 `true` 可禁用 state field。
>
> **disableZipCode** `boolean`
>
> 设置为 `true` 可禁用 ZIP code field。
>
> **paymentCurrency** `string`
>
> Payment currency，例如 `USD`。
>
> **showCurrencySelector** `boolean` (default: true)
>
> 显示或隐藏 currency selector。
>
> **paymentAmount** `number`
>
> 固定收取的金额，以 major currency units 表示，例如 \$12.50 对应 `12.5`。仅适用于 Pay What You Want products；如果低于 product 的 minimum price，则会被忽略。
>
> **showDiscounts** `boolean` (default: true)
>
> 显示或隐藏 discounts section。
>
> **metadata\_**\* `string`
>
> 任何以 `metadata_` 开头的 query parameter 都会作为 metadata 传递。
>
> handler 会将 config 中的 `returnUrl` 作为 `redirect_url` 添加到 link。
>
> > [!WARNING]
> >
> > 如果 `productId` 缺失，handler 将返回 400 response。无效的 query parameters 和不存在的 product IDs 也会返回 400。
>
> ### Response Format
>
> Static checkout 返回包含 checkout URL 的 JSON response。在 test mode 中，URL 使用 `test.checkout.dodopayments.com`。
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/..."
> }
> ```

> **Dynamic Checkout (POST)**
>
> * 在 POST request 中将 parameters 作为 JSON body 发送。
> * 支持 one-time 和 recurring payments。
> * `billing` 和 `customer` 为必需项。
> * 所有受支持的 body fields，请参阅：
>   * [One Time Payment Product 的 Request body](https://docs.dodopayments.com/api-reference/payments/post-payments)
>
>   * [Subscription Product 的 Request body](https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions)
>
> > [!WARNING]
> >
> > Dynamic checkout 代理已弃用的 `POST /payments` 和 `POST /subscriptions` endpoints。它会继续支持现有 integrations，但新 integrations 应使用 checkout sessions。
>
> ### Response Format
>
> Dynamic checkout 返回包含 checkout URL 的 JSON response：
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/..."
> }
> ```

> **Checkout Sessions (POST)**
>
> Checkout sessions 为 one-time purchases 和 subscriptions 创建 hosted checkout，并提供完整的 customization 控制。`product_cart` 是唯一必需的 field。如果 body 中没有 `return_url`，handler 将使用 config 中的 `returnUrl`。
>
> 如需了解详细信息和所有受支持的 fields，请参阅 [Checkout Sessions Integration Guide](https://docs.dodopayments.com/developer-resources/checkout-session)。
>
> 使用 `payment_method_id` 创建的 session 不会返回 checkout URL，因此 handler 会响应 400。要向 saved payment method 收款，请改用 SDK 创建 session。
>
> ### Response Format
>
> Checkout sessions 返回包含 checkout URL 的 JSON response：
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/session/..."
> }
> ```

## Customer Portal Route Handler

Customer Portal route handler 会为你传入的 customer 创建 Customer Portal session，并将浏览器重定向到该 session。

> [!WARNING]
>
> handler 不会检查调用者的身份。任何使用 customer ID 请求它的人都可以获得该 customer 的 portal。请使用自己的 authentication 保护此 route，并且只传入已登录用户的 customer ID。

### Query Parameters

**customer\_id** `string` *required*

portal session 的 customer ID，例如 `?customer_id=cus_123`。

**send\_email** `boolean`

如果设置为 `true`，Dodo Payments 还会将 portal link 发送到客户的 email。

> [!WARNING]
>
> 从 `@dodopayments/nuxt` 0.2.11 开始，如果缺少 `customer_id`，handler 将返回 HTTP `400`；如果无法创建 portal session，则返回 HTTP `500`。在此之前的版本在这两种情况下都会返回 HTTP `200`，并附带类似 `{ "status": 400, "body": "Missing customer_id in query parameters" }` 的 JSON body。若要依赖 HTTP status，请升级到 0.2.11 或更高版本。

## Webhook Route Handler

webhook route handler 会在运行你的代码前验证每个 request：

* **Method：** 仅支持 POST requests。其他 methods 返回 405。
* **Signature Verification：** 根据 [Standard Webhooks](https://standardwebhooks.com/) specification，使用 `webhookKey` 验证 raw request body 以及 `webhook-id`、`webhook-timestamp` 和 `webhook-signature` headers。验证失败时返回 401。
* **Payload Validation：** 使用 Zod 验证 payload。payload 无效时返回 400。
* **Error Handling：**
  * 401：Invalid signature
  * 400：Invalid payload
  * 500：验证期间发生 Internal error
* **Event Routing：** 对每个 event 调用 `onPayload`，然后调用该 event type 对应的 handler，并返回 200。

adaptor 不会捕获你的 handlers 抛出的 errors。它们会传播到 Nuxt，并导致 request 失败。

### 支持的 Webhook Event Handlers

每个 handler 都会接收其 event type 对应的已验证 payload：

```typescript TypeScript expandable theme={null}
onPayload?: (payload: WebhookPayload) => Promise<void>;
onPaymentSucceeded?: (payload: WebhookPayload) => Promise<void>;
onPaymentFailed?: (payload: WebhookPayload) => Promise<void>;
onPaymentProcessing?: (payload: WebhookPayload) => Promise<void>;
onPaymentCancelled?: (payload: WebhookPayload) => Promise<void>;
onRefundSucceeded?: (payload: WebhookPayload) => Promise<void>;
onRefundFailed?: (payload: WebhookPayload) => Promise<void>;
onDisputeOpened?: (payload: WebhookPayload) => Promise<void>;
onDisputeExpired?: (payload: WebhookPayload) => Promise<void>;
onDisputeAccepted?: (payload: WebhookPayload) => Promise<void>;
onDisputeCancelled?: (payload: WebhookPayload) => Promise<void>;
onDisputeChallenged?: (payload: WebhookPayload) => Promise<void>;
onDisputeWon?: (payload: WebhookPayload) => Promise<void>;
onDisputeLost?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionActive?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionOnHold?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionRenewed?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionPlanChanged?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionCancelled?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionFailed?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionExpired?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionUpdated?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionPaused?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionUnpaused?: (payload: WebhookPayload) => Promise<void>;
onSubscriptionUpdatePaymentMethod?: (payload: WebhookPayload) => Promise<void>;
onLicenseKeyCreated?: (payload: WebhookPayload) => Promise<void>;
onAbandonedCheckoutDetected?: (payload: WebhookPayload) => Promise<void>;
onAbandonedCheckoutRecovered?: (payload: WebhookPayload) => Promise<void>;
onDunningStarted?: (payload: WebhookPayload) => Promise<void>;
onDunningRecovered?: (payload: WebhookPayload) => Promise<void>;
onCreditAdded?: (payload: WebhookPayload) => Promise<void>;
onCreditDeducted?: (payload: WebhookPayload) => Promise<void>;
onCreditExpired?: (payload: WebhookPayload) => Promise<void>;
onCreditRolledOver?: (payload: WebhookPayload) => Promise<void>;
onCreditRolloverForfeited?: (payload: WebhookPayload) => Promise<void>;
onCreditOverageCharged?: (payload: WebhookPayload) => Promise<void>;
onCreditOverageReset?: (payload: WebhookPayload) => Promise<void>;
onCreditManualAdjustment?: (payload: WebhookPayload) => Promise<void>;
onCreditBalanceLow?: (payload: WebhookPayload) => Promise<void>;
onEntitlementGrantCreated?: (payload: WebhookPayload) => Promise<void>;
onEntitlementGrantDelivered?: (payload: WebhookPayload) => Promise<void>;
onEntitlementGrantFailed?: (payload: WebhookPayload) => Promise<void>;
onEntitlementGrantRevoked?: (payload: WebhookPayload) => Promise<void>;
onPayoutCreated?: (payload: WebhookPayload) => Promise<void>;
onPayoutOnHold?: (payload: WebhookPayload) => Promise<void>;
onPayoutInProgress?: (payload: WebhookPayload) => Promise<void>;
onPayoutFailed?: (payload: WebhookPayload) => Promise<void>;
onPayoutSuccess?: (payload: WebhookPayload) => Promise<void>;
```

有关每个 event 的含义，请参阅 [Webhook Event Guide](/developer-resources/webhooks/intents/webhook-events-guide)。

***

## LLM Prompt

将此 prompt 复制到 AI coding assistant 中，让它将该 module 添加到你的项目。要同时为 agent 提供 Dodo Payments docs 和 skills，请安装 [Agent Plugin](/developer-resources/build-with-ai-coding-agents)。

```text expandable theme={null}
You are an expert Nuxt developer assistant. Your task is to guide a user through integrating the @dodopayments/nuxt module into their existing Nuxt project.

The @dodopayments/nuxt module provides API route handlers for Dodo Payments' Checkout, Customer Portal, and Webhook functionalities, designed for Nuxt 3 server routes. The module auto-imports checkoutHandler, customerPortalHandler, and Webhooks into server routes, so the route files need no import statements.

First, install the necessary package:

npm install @dodopayments/nuxt

Second, add the configuration to nuxt.config.ts

export default defineNuxtConfig({
  modules: ["@dodopayments/nuxt"],
  devtools: { enabled: true },
  compatibilityDate: "2025-02-25",
  runtimeConfig: {
    private: {
      bearerToken: process.env.NUXT_PRIVATE_BEARER_TOKEN,
      webhookKey: process.env.NUXT_PRIVATE_WEBHOOK_KEY,
      environment: process.env.NUXT_PRIVATE_ENVIRONMENT,
      returnUrl: process.env.NUXT_PRIVATE_RETURN_URL
    },
  }
});

Here's how you should structure your response:

    Ask the user which functionalities they want to integrate.

"Which parts of the @dodopayments/nuxt module would you like to integrate into your project? You can choose one or more of the following:

    Checkout API Route (for handling product checkouts)
    Customer Portal API Route (for managing customer subscriptions/details)
    Webhook API Route (for receiving Dodo Payments webhook events)
    All (integrate all three)"

    Based on the user's selection, provide detailed integration steps for each chosen functionality.

If Checkout API Route is selected:

Purpose: This route returns a JSON response with a checkout_url for the Dodo Payments checkout page.
File Creation: Create a new file at server/routes/api/checkout.get.ts in your Nuxt project.

Code Snippet:

// server/routes/api/checkout.get.ts

export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment, returnUrl },
  } = useRuntimeConfig();

  const handler = checkoutHandler({
    bearerToken: bearerToken,
    environment: environment as "test_mode" | "live_mode",
    returnUrl: returnUrl,
  });

  return handler(event);
});

Configuration & Usage:
- bearerToken: Your Dodo Payments API key. Set via the NUXT_PRIVATE_BEARER_TOKEN environment variable.
- returnUrl: (Optional) The URL to redirect the user to after a successful checkout.
- environment: (Optional) "test_mode" or "live_mode". Defaults to "live_mode".
- type: (Optional) On a POST route (server/routes/api/checkout.post.ts), set "dynamic" for dynamic checkout or "session" for checkout sessions. Any value other than "dynamic" serves checkout sessions.

Static Checkout (GET) Query Parameters:
- productId (required): Product identifier (e.g., ?productId=pdt_nZuwz45WAs64n3l07zpQR)
- quantity (optional): Quantity of the product
- Customer Fields (optional): fullName, firstName, lastName, email, country, addressLine, city, state, zipCode
- Disable Flags (optional, set to true to disable): disableFullName, disableFirstName, disableLastName, disableEmail, disableCountry, disableAddressLine, disableCity, disableState, disableZipCode
- Advanced Controls (optional): paymentCurrency, showCurrencySelector, paymentAmount, showDiscounts
- Metadata (optional): Any query parameter starting with metadata_ (e.g., ?metadata_userId=abc123)

Dynamic Checkout (POST): Parameters are sent as a JSON body. Supports both one-time and recurring payments. For a complete list of supported POST body fields, refer to:
- Docs - One Time Payment Product: https://docs.dodopayments.com/api-reference/payments/post-payments
- Docs - Subscription Product: https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions

Checkout Sessions (POST) - (Recommended) A more customizable checkout experience. Returns JSON with checkout_url: Parameters are sent as a JSON body, and product_cart is required. Supports both one-time and recurring payments. Returns: {"checkout_url": "https://checkout.dodopayments.com/session/..."}. For a complete list of supported fields, refer to:

  Checkout Sessions Integration Guide: https://docs.dodopayments.com/developer-resources/checkout-session

Error Handling: If productId is missing or other query parameters are invalid, the handler will return a 400 response.

If Customer Portal API Route is selected:

Purpose: This route redirects a customer to their Dodo Payments customer portal. It does not authenticate the caller, so protect the route and pass only the signed-in user's customer ID.
File Creation: Create a new file at server/routes/api/customer-portal.get.ts in your Nuxt project.

Code Snippet:

// server/routes/api/customer-portal.get.ts

export default defineEventHandler((event) => {
  const {
    private: { bearerToken, environment },
  } = useRuntimeConfig();

  const handler = customerPortalHandler({
    bearerToken,
    environment: environment as "test_mode" | "live_mode",
  });

  return handler(event);
});

Query Parameters:
- customer_id (required): The customer ID for the portal session (e.g., ?customer_id=cus_123)
- send_email (optional, boolean): If set to true, sends an email to the customer with the portal link.
- Returns 400 if customer_id is missing, and 500 if the portal session cannot be created (@dodopayments/nuxt 0.2.11 or later).

If Webhook API Route is selected:

Purpose: This route processes incoming webhook events from Dodo Payments, allowing your application to react to events like successful payments, refunds, or subscription changes.
File Creation: Create a new file at server/routes/api/webhook.post.ts in your Nuxt project.

Code Snippet:

// server/routes/api/webhook.post.ts

export default defineEventHandler((event) => {
  const {
    private: { webhookKey },
  } = useRuntimeConfig();

  const handler = Webhooks({
    webhookKey: webhookKey,
    onPayload: async (payload) => {
      // handle the payload
    },
    // ... other event handlers for granular control
  });

  return handler(event);
});

Handler Details:
- Method: Only POST requests are supported. Other methods return 405.
- Signature Verification: The handler verifies the webhook signature using webhookKey and returns 401 if verification fails.
- Payload Validation: The payload is validated with Zod. Returns 400 for invalid payloads.

Error Handling:
- 401: Invalid signature
- 400: Invalid payload
- 500: Internal error during verification

Event Routing: Calls onPayload for every event, then the handler for the event's type. Supported event handlers include:
- onPayload?: (payload: WebhookPayload) => Promise<void>
- onPaymentSucceeded?: (payload: WebhookPayload) => Promise<void>
- onPaymentFailed?: (payload: WebhookPayload) => Promise<void>
- onPaymentProcessing?: (payload: WebhookPayload) => Promise<void>
- onPaymentCancelled?: (payload: WebhookPayload) => Promise<void>
- onRefundSucceeded?: (payload: WebhookPayload) => Promise<void>
- onRefundFailed?: (payload: WebhookPayload) => Promise<void>
- onDisputeOpened?: (payload: WebhookPayload) => Promise<void>
- onDisputeExpired?: (payload: WebhookPayload) => Promise<void>
- onDisputeAccepted?: (payload: WebhookPayload) => Promise<void>
- onDisputeCancelled?: (payload: WebhookPayload) => Promise<void>
- onDisputeChallenged?: (payload: WebhookPayload) => Promise<void>
- onDisputeWon?: (payload: WebhookPayload) => Promise<void>
- onDisputeLost?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionActive?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionOnHold?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionRenewed?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionPlanChanged?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionCancelled?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionFailed?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionExpired?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionUpdated?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionPaused?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionUnpaused?: (payload: WebhookPayload) => Promise<void>
- onSubscriptionUpdatePaymentMethod?: (payload: WebhookPayload) => Promise<void>
- onLicenseKeyCreated?: (payload: WebhookPayload) => Promise<void>
- onAbandonedCheckoutDetected?: (payload: WebhookPayload) => Promise<void>
- onAbandonedCheckoutRecovered?: (payload: WebhookPayload) => Promise<void>
- onDunningStarted?: (payload: WebhookPayload) => Promise<void>
- onDunningRecovered?: (payload: WebhookPayload) => Promise<void>
- onCreditAdded?: (payload: WebhookPayload) => Promise<void>
- onCreditDeducted?: (payload: WebhookPayload) => Promise<void>
- onCreditExpired?: (payload: WebhookPayload) => Promise<void>
- onCreditRolledOver?: (payload: WebhookPayload) => Promise<void>
- onCreditRolloverForfeited?: (payload: WebhookPayload) => Promise<void>
- onCreditOverageCharged?: (payload: WebhookPayload) => Promise<void>
- onCreditOverageReset?: (payload: WebhookPayload) => Promise<void>
- onCreditManualAdjustment?: (payload: WebhookPayload) => Promise<void>
- onCreditBalanceLow?: (payload: WebhookPayload) => Promise<void>
- onEntitlementGrantCreated?: (payload: WebhookPayload) => Promise<void>
- onEntitlementGrantDelivered?: (payload: WebhookPayload) => Promise<void>
- onEntitlementGrantFailed?: (payload: WebhookPayload) => Promise<void>
- onEntitlementGrantRevoked?: (payload: WebhookPayload) => Promise<void>
- onPayoutCreated?: (payload: WebhookPayload) => Promise<void>
- onPayoutOnHold?: (payload: WebhookPayload) => Promise<void>
- onPayoutInProgress?: (payload: WebhookPayload) => Promise<void>
- onPayoutFailed?: (payload: WebhookPayload) => Promise<void>
- onPayoutSuccess?: (payload: WebhookPayload) => Promise<void>

Environment Variable Setup:
To ensure the module functions correctly, set up the following environment variables in your Nuxt project's deployment environment (e.g., Vercel, Netlify, AWS, etc.). A built Nuxt server does not read the .env file, and Nuxt overrides runtime config values at runtime only from variables whose names match the config path:
- NUXT_PRIVATE_BEARER_TOKEN: Your Dodo Payments API Key (required for Checkout and Customer Portal).
- NUXT_PRIVATE_WEBHOOK_KEY: Your Dodo Payments Webhook Secret (required for Webhook handler).
- NUXT_PRIVATE_ENVIRONMENT: (Optional) "test_mode" or "live_mode". Defaults to "live_mode".
- NUXT_PRIVATE_RETURN_URL: (Optional) The URL to redirect to after a successful checkout (for Checkout handler).

Usage in your code:
bearerToken: useRuntimeConfig().private.bearerToken
webhookKey: useRuntimeConfig().private.webhookKey

Important: Never commit sensitive environment variables directly into your version control. Use environment variables for all sensitive information.

If the user needs assistance setting up environment variables for their specific deployment environment, ask them what platform they are using (e.g., Vercel, Netlify, AWS, etc.), and provide guidance.
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.