> ## 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.

# Remix 适配器

> 使用 @dodopayments/remix 包将 Dodo Payments checkout、Customer Portal 和 webhook 处理程序添加到 Remix loaders 和 actions 中。

`@dodopayments/remix` 包为你的 Remix 应用提供三个请求处理程序。`Checkout` 返回 checkout URL，`CustomerPortal` 将客户发送到 Customer Portal，而 `Webhooks` 验证 webhook 事件并将其路由到你的代码。每个处理程序都接收一个 `Request` 并返回一个 `Response`，因此你可以从路由的 `loader` 或 `action` 中调用它。

> **[Checkout Handler](#checkout-route-handler)**
>
> 从 Remix 应用创建 checkout URL。

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

> **[Webhooks](#webhook-route-handler)**
>
> 接收并验证 Dodo Payments webhook 事件。

## 安装

**1. Install the Package**

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

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

该包将 Remix 2（`remix` 2.16.8 或更高版本）和 `zod` 3.25 或更高版本列为 peer dependencies。

**2. Set Up Environment Variables**

在项目根目录创建一个 `.env` 文件：

```env expandable theme={null}
DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
DODO_PAYMENTS_RETURN_URL=https://yourdomain.com/checkout/success
# test_mode or live_mode
DODO_PAYMENTS_ENVIRONMENT=test_mode
```

在 **Developer → API Keys** 下创建 API key。在 **Developer → Webhooks** 下添加 webhook endpoint，并将其 signing secret 复制到 `DODO_PAYMENTS_WEBHOOK_KEY`。`DODO_PAYMENTS_RETURN_URL` 是客户完成 checkout 后到达的页面。如果不传入 environment，处理程序将使用 `live_mode`。

> [!WARNING]
>
> 切勿将 `.env` 文件或 secrets 提交到版本控制系统。

## Route Handler 示例

> [!NOTE]
>
> 这些示例是 Remix resource routes，它们为 GET 请求导出一个 `loader`，或为 POST 请求导出一个 `action`，且不包含组件。对于 flat file routes，`app/routes/api.checkout.tsx` 提供 `/api/checkout`。

**Checkout Handler**

> [!NOTE]
>
> 使用此处理程序将 Dodo Payments checkout 添加到 Remix 应用。`loader` 提供 static checkout。`action` 在此提供 dynamic checkout。要提供 checkout sessions（推荐流程），请改为从 `action` 返回 `checkoutSessionHandler(request)`。

```typescript Remix Route Handler expandable theme={null}
// app/routes/api.checkout.tsx
import { Checkout } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const checkoutGetHandler = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
    type: "static"
});

const checkoutPostHandler = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
    type: "dynamic", // for dynamic checkout
});

const checkoutSessionHandler = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
    type: "session", // for checkout sessions
});

export const loader = ({ request }: LoaderFunctionArgs) => checkoutGetHandler(request);
export const action = ({ request }: LoaderFunctionArgs) => {
    // You can conditionally route to different handlers based on your needs
    // For checkout sessions, use checkoutSessionHandler(request)
    return checkoutPostHandler(request);
};
```

```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"
}'
```

当 `action` 返回 `checkoutSessionHandler(request)` 时，checkout session 请求即可正常工作。

**Customer Portal Handler**

> [!NOTE]
>
> 使用此处理程序将客户发送到 Dodo Payments Customer Portal，以便他们管理订阅和详细信息。

```typescript Remix Route Handler expandable theme={null}
// app/routes/api.customer-portal.tsx
import { CustomerPortal } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const customerPortalHandler = CustomerPortal({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode"
});

export const loader = ({ request }: LoaderFunctionArgs) => customerPortalHandler(request);
```

```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 Handler**

> [!NOTE]
>
> 使用此处理程序在 Remix 应用中接收 Dodo Payments webhook 事件并验证其签名。

```typescript Remix Route Handler expandable theme={null}
// app/routes/api.webhook.tsx
import { Webhooks } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const webhookHandler = Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY!,
onPayload: async (payload) => {
    //Handle Payload Here
    console.log(payload)
}
});
export const action = ({ request }: LoaderFunctionArgs) => webhookHandler(request);
```

## Checkout Route Handler

checkout 处理程序支持使用 Dodo Payments 收款的三种方式：

* **Static Payment Links：** 可分享的 URL，无需代码即可收款。
* **Dynamic Payment Links：** 使用自定义详细信息生成的 payment links。它们使用已弃用的 endpoints。
* **Checkout Sessions：** 支持 product cart、客户详细信息和自定义选项的托管 checkout。这是推荐的流程。

`Checkout` 接收以下选项：

| 选项 | 类型 | 描述 |
| - | - | - |
| `bearerToken` | `string` | 你的 Dodo Payments API key。 |
| `environment` | `string` | `test_mode` 或 `live_mode`。默认为 `live_mode`。 |
| `returnUrl` | `string` | 可选。checkout 在付款后将客户重定向到的 URL。POST body 中的 `return_url` 优先级更高。 |
| `type` | `string` | 可选。为你的 `loader` 调用的处理程序指定 `static`（默认值）。对于 POST 请求，`dynamic` 选择 dynamic checkout，任何其他值或不传值都选择 checkout sessions。 |

> **Static Checkout (GET)**
>
> ### 支持的 Query Parameters
>
> **productId** `string` *required*
>
> Product identifier，例如 `?productId=pdt_nZuwz45WAs64n3l07zpQR`。
>
> **quantity** `integer` (default: 1)
>
> 产品数量。
>
> **fullName** `string`
>
> 客户的全名。如果提供了 `firstName` 或 `lastName`，则忽略此项。
>
> **firstName** `string`
>
> 客户的名字。
>
> **lastName** `string`
>
> 客户的姓氏。
>
> **email** `string`
>
> 客户的电子邮件地址。
>
> **country** `string`
>
> 客户的国家，以 ISO 3166-1 alpha-2 代码表示。
>
> **addressLine** `string`
>
> 客户的地址行。
>
> **city** `string`
>
> 客户所在的城市。
>
> **state** `string`
>
> 客户所在的州或省。
>
> **zipCode** `string`
>
> 客户的 ZIP 或邮政编码。
>
> **disableFullName** `boolean`
>
> 设置为 `true` 以禁用全名字段。
>
> **disableFirstName** `boolean`
>
> 设置为 `true` 以禁用名字字段。
>
> **disableLastName** `boolean`
>
> 设置为 `true` 以禁用姓氏字段。
>
> **disableEmail** `boolean`
>
> 设置为 `true` 以禁用电子邮件字段。
>
> **disableCountry** `boolean`
>
> 设置为 `true` 以禁用国家字段。
>
> **disableAddressLine** `boolean`
>
> 设置为 `true` 以禁用地址行字段。
>
> **disableCity** `boolean`
>
> 设置为 `true` 以禁用城市字段。
>
> **disableState** `boolean`
>
> 设置为 `true` 以禁用州字段。
>
> **disableZipCode** `boolean`
>
> 设置为 `true` 以禁用 ZIP code 字段。
>
> **paymentCurrency** `string`
>
> 付款货币，例如 `USD`。
>
> **showCurrencySelector** `boolean` (default: true)
>
> 显示或隐藏货币选择器。
>
> **paymentAmount** `number`
>
> 固定收取的金额，以主要货币单位表示，例如 `12.5` 表示 \$12.50。仅适用于 Pay What You Want 产品；如果低于产品的最低价格，则会忽略该值。
>
> **showDiscounts** `boolean` (default: true)
>
> 显示或隐藏折扣部分。
>
> **metadata\_**\* `string`
>
> 任何以 `metadata_` 开头的 query parameter 都会作为 metadata 传递。
>
> 处理程序会将其配置中的 `returnUrl` 作为 `redirect_url` 添加到链接中。
>
> > [!WARNING]
> >
> > 如果缺少 `productId`，处理程序将返回 400 响应。无效的 query parameters 和不存在的 product IDs 也会返回 400。
>
> ### Response Format
>
> Static checkout 返回包含 checkout URL 的 JSON 响应。在 test mode 下，URL 使用 `test.checkout.dodopayments.com`。
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/..."
> }
> ```

> **Dynamic Checkout (POST)**
>
> * 在 POST 请求中将参数作为 JSON body 发送。
> * 同时支持一次性付款和 recurring payments。
> * `billing` 和 `customer` 为必填项。
> * 如需查看所有支持的 body 字段，请参阅：
>   * [一次性付款产品的 Request body](https://docs.dodopayments.com/api-reference/payments/post-payments.md)
>
>   * [Subscription Product 的 Request body](https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions.md)
>
> > [!WARNING]
> >
> > Dynamic checkout 代理已弃用的 `POST /payments` 和 `POST /subscriptions` endpoints。它会继续支持现有 integrations，但新 integrations 应使用 checkout sessions。
>
> ### Response Format
>
> Dynamic checkout 返回包含 checkout URL 的 JSON 响应：
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/..."
> }
> ```

> **Checkout Sessions (POST)**
>
> Checkout sessions 为一次性购买和 subscriptions 创建 hosted checkout，并提供完整的自定义控制。`product_cart` 是唯一的必填字段。如果 body 中没有 `return_url`，处理程序将使用其配置中的 `returnUrl`。
>
> 如需了解更多详细信息和所有支持的字段，请参阅 [Checkout Sessions Integration Guide](https://docs.dodopayments.com/developer-resources/checkout-session.md)。
>
> 使用 `payment_method_id` 创建的 session 不会返回 checkout URL，因此处理程序会返回 400。若要向已保存的 payment method 收款，请改用 SDK 创建 session。
>
> ### Response Format
>
> Checkout sessions 返回包含 checkout URL 的 JSON 响应：
>
> ```json theme={null}
> {
>   "checkout_url": "https://checkout.dodopayments.com/session/..."
> }
> ```

## Customer Portal Route Handler

Customer Portal route handler 为你传入的客户创建 Customer Portal session，并通过 307 响应将浏览器重定向到该 session。

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

### Query Parameters

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

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

**send\_email** `boolean`

如果设置为 `true`，Dodo Payments 还会通过电子邮件将 portal link 发送给客户。

> [!WARNING]
>
> 如果缺少 `customer_id`，则返回 400；如果无法创建 portal session，则返回 500。

## Webhook Route Handler

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

* **Method：** 仅支持 POST 请求。其他 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：签名无效
  * 400：payload 无效
  * 500：验证期间发生内部错误
* **Event Routing：** 对每个事件调用 `onPayload`，然后调用该事件类型对应的处理程序，并返回 200。

该 adaptor 不会捕获你的 handlers 抛出的 errors。这些 errors 会传播到 Remix，并导致请求失败。

### 支持的 Webhook Event Handlers

每个处理程序都会接收其事件类型对应的已验证 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>;
```

有关每个事件含义的说明，请参阅 [Webhook Event Guide](https://docs.dodopayments.com/developer-resources/webhooks/intents/webhook-events-guide.md)。

***

## LLM 提示词

将此提示词复制到 AI coding assistant 中，让它将 adaptor 添加到你的项目中。若还希望为 agent 提供 Dodo Payments 文档和 skills，请安装 [Agent Plugin](https://docs.dodopayments.com/developer-resources/build-with-ai-coding-agents.md)。

```text expandable theme={null}

You are an expert Remix developer assistant. Your task is to guide a user through integrating the @dodopayments/remix adapter into their existing Remix project.

The @dodopayments/remix adapter provides route handlers for Dodo Payments' Checkout, Customer Portal, and Webhook functionalities, designed for Remix route handlers.

First, install the necessary packages. Use the package manager appropriate for your project (npm, yarn, or bun) based on the presence of lock files (e.g., package-lock.json for npm, yarn.lock for yarn, bun.lockb for bun):

npm install @dodopayments/remix

Here's how you should structure your response:

    Ask the user which functionalities they want to integrate.

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

    Checkout Route Handler (for handling product checkouts)

    Customer Portal Route Handler (for managing customer subscriptions/details)

    Webhook Route Handler (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 Route Handler is selected:

Purpose: This handler returns a JSON response with a checkout_url for the Dodo Payments checkout page. The loader serves static checkout (GET). The action serves dynamic checkout or checkout sessions (POST); checkout sessions are recommended for new integrations.
File Creation: Create a new file at app/routes/api.checkout.tsx in your Remix project.

Code Snippet:

// app/routes/api.checkout.tsx
import { Checkout } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const checkoutGetHandler = Checkout({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
  type: "static",
});

const checkoutPostHandler = Checkout({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
  type: "dynamic", // for dynamic checkout
});

const checkoutSessionHandler = Checkout({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
  type: "session", // for checkout sessions
});

export const loader = ({ request }: LoaderFunctionArgs) => checkoutGetHandler(request);

export const action = ({ request }: LoaderFunctionArgs) => {
  // You can conditionally route to different handlers based on your needs
  // For checkout sessions, use checkoutSessionHandler(request)
  return checkoutPostHandler(request);
};

If Customer Portal Route Handler is selected:

Purpose: This handler 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 app/routes/api.customer-portal.tsx in your Remix project.

Code Snippet:

// app/routes/api.customer-portal.tsx
import { CustomerPortal } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const customerPortalHandler = CustomerPortal({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode"
});

export const loader = ({ request }: LoaderFunctionArgs) => customerPortalHandler(request);

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.

If Webhook Route Handler is selected:

Purpose: This handler 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 app/routes/api.webhook.tsx in your Remix project.

Code Snippet:

// app/routes/api.webhook.tsx
import { Webhooks } from "@dodopayments/remix";
import type { LoaderFunctionArgs } from "@remix-run/node";

const webhookHandler = Webhooks({
  webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY!,
  onPayload: async (payload) => {
    //Handle Payload Here
    console.log(payload)
  }
});

export const action = ({ request }: LoaderFunctionArgs) => webhookHandler(request);

Handler Details:

    Method: Only POST requests are supported. Other methods return 405.

    Signature Verification: The handler verifies the webhook signature using the 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 Webhook Event Handlers:

    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 adapter functions correctly, you will need to manually set up the following environment variables in your Remix project's deployment environment (e.g., Vercel, Netlify, AWS, etc.):

    DODO_PAYMENTS_API_KEY: Your Dodo Payments API Key (required for Checkout and Customer Portal).

    DODO_PAYMENTS_RETURN_URL: (Optional) The URL to redirect to after a successful checkout (for Checkout handler).

    DODO_PAYMENTS_ENVIRONMENT: (Optional) "test_mode" or "live_mode". Defaults to "live_mode".

    DODO_PAYMENTS_WEBHOOK_KEY: Your Dodo Payments Webhook Secret (required for Webhook handler).

Example .env file:

DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_RETURN_URL=your-return-url
DODO_PAYMENTS_ENVIRONMENT=test_mode
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret

Usage in your code:

bearerToken: process.env.DODO_PAYMENTS_API_KEY
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY!

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. You can also add comments to their PR or chat depending on the context

```


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