@dodopayments/convex

中文文档
0.2.16发布于 2026/11/03TypeScriptESM + CJS构建来源已验证近 30 天下载 2.5万

npm version

原始使用文档
文档目录10 节
  1. Installation
  2. Quick Start
  3. 1. Add Component to Convex Config
  4. 2. Set Up Environment Variables
  5. 3. Create Internal Query
  6. 4. Configure DodoPayments Component
  7. 5. Define Payment Actions
  8. 6. Frontend Usage
  9. 7. Set Up Webhooks (Optional)
  10. Prompt for LLM

Dodo Payments Convex Component

npm version

This component is the official way to integrate the Dodo Payments in your Convex project.

Features:

  • Checkout Session: Integrate Dodo Payments Checkout with a couple of lines code.

  • Customer Portal: Allow customers to manage subscriptions and details

  • Webhooks: Handle webhooks efficiently. Just write your business logic and handle the events you want. Webhook verification is taken care by us

Detailed documentation can be found at Dodo Payments Convex Component

Installation

npm install @dodopayments/convex

Quick Start

Note: This component does not define a schema. Define your own schema based on your application's needs.

1. Add Component to Convex Config

// convex/convex.config.ts
import { defineApp } from "convex/server";
import dodopayments from "@dodopayments/convex/convex.config";

const app = defineApp();
app.use(dodopayments);
export default app;

2. Set Up Environment Variables

Create a Dodo Payments account and get the API_KEY and WEBHOOK_SECRET

Add your environment variables in the Convex dashboard (Settings → Environment Variables). You can open the dashboard by running:

npx convex dashboard

Set the following variables:

  • DODO_PAYMENTS_API_KEY=your-api-key
  • DODO_PAYMENTS_ENVIRONMENT=test_mode
  • DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret (if using webhooks)

Note: Convex backend functions only read environment variables set in the Convex dashboard. .env files are ignored. Always set secrets in the Convex dashboard for both production and development.

3. Create Internal Query

First, create an internal query to fetch customers from your database. This will be used in the payment functions to identify customers.

// convex/customers.ts
import { internalQuery } from "./_generated/server";
import { v } from "convex/values";

// Internal query to fetch customer by auth ID
// Customize this based on your database schema and authentication provider
export const getByAuthId = internalQuery({
  args: { authId: v.string() },
  handler: async (ctx, { authId }) => {
    return await ctx.db
      .query("customers")
      .withIndex("by_auth_id", (q) => q.eq("authId", authId))
      .first();
  },
});

4. Configure DodoPayments Component

// convex/dodo.ts
import { DodoPayments, DodoPaymentsClientConfig } from "@dodopayments/convex";
import { components } from "./_generated/api";
import { internal } from "./_generated/api";

export const dodo = new DodoPayments(components.dodopayments, {
  // This function maps your Convex customer to a Dodo Payments customer
  // Customize it based on your authentication provider and customer database

  identify: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      return null; // Customer is not logged in
    }

    // Use ctx.runQuery() to lookup customer from your database
    const customer = await ctx.runQuery(internal.customers.getByAuthId, {
      authId: identity.subject,
    });

    if (!customer) {
      return null; // Customer not found in database
    }

    return {
      dodoCustomerId: customer.dodoCustomerId, // Replace customer.dodoCustomerId with your field storing Dodo Payments customer ID
    };
  },
  apiKey: process.env.DODO_PAYMENTS_API_KEY!,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as
    | "test_mode"
    | "live_mode",
} as DodoPaymentsClientConfig);

// Export the API methods for use in your app
export const { checkout, customerPortal } = dodo.api();

5. Define Payment Actions

// convex/payments.ts
import { action } from "./_generated/server";
import { v } from "convex/values";
import { checkout } from "./dodo";

export const createCheckout = action({
  args: {
    product_cart: v.array(
      v.object({
        product_id: v.string(),
        quantity: v.number(),
      }),
    ),
    returnUrl: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    return await checkout(ctx, {
      payload: {
        product_cart: args.product_cart,
        return_url: args.returnUrl,
        billing_currency: "USD",
        feature_flags: {
          allow_discount_code: true,
        },
      },
    });
  },
});

6. Frontend Usage

import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";

export function CheckoutButton() {
  const createCheckout = useAction(api.payments.createCheckout);

  const handleCheckout = async () => {
    const { checkout_url } = await createCheckout({
      product_cart: [{ product_id: "prod_123", quantity: 1 }],
    });
    window.location.href = checkout_url;
  };

  return <button onClick={handleCheckout}>Buy Now</button>;
}

7. Set Up Webhooks (Optional)

For handling Dodo Payments webhooks, create a file convex/http.ts:

// convex/http.ts
import { createDodoWebhookHandler } from "@dodopayments/convex";
import { httpRouter } from "convex/server";
import { internal } from "./_generated/api";

const http = httpRouter();

http.route({
  path: "/dodopayments-webhook",
  method: "POST",
  handler: createDodoWebhookHandler({
    // Handle successful payments
    onPaymentSucceeded: async (ctx, payload) => {
      console.log("🎉 Payment Succeeded!");
      // Use Convex context to persist payment data
      await ctx.runMutation(internal.webhooks.createPayment, {
        paymentId: payload.data.payment_id,
        businessId: payload.business_id,
        customerEmail: payload.data.customer.email,
        amount: payload.data.total_amount,
        currency: payload.data.currency,
        status: payload.data.status,
        webhookPayload: JSON.stringify(payload),
      });
    },

    // Handle subscription activation
    onSubscriptionActive: async (ctx, payload) => {
      console.log("🎉 Subscription Activated!");
      // Use Convex context to persist subscription data
      await ctx.runMutation(internal.webhooks.createSubscription, {
        subscriptionId: payload.data.subscription_id,
        businessId: payload.business_id,
        customerEmail: payload.data.customer.email,
        status: payload.data.status,
        webhookPayload: JSON.stringify(payload),
      });
    },
    // Add other event handlers as needed
  }),
});

export default http;

Important: Make sure to define the corresponding database mutations in your Convex backend for each webhook event you want to handle. For example, create a createPayment mutation to record successful payments or a createSubscription mutation to manage subscription state.

Important: All webhook handlers receive the Convex ActionCtx as the first parameter, allowing you to use ctx.runQuery() and ctx.runMutation() to interact with your database.

Add your webhook secret in the Convex dashboard (Settings → Environment Variables):

  • DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret

Prompt for LLM

You are an expert Convex developer assistant. Your task is to guide a user through integrating the @dodopayments/convex component into their existing Convex application.

The @dodopayments/convex adapter provides a Convex component for Dodo Payments' Checkout, Customer Portal, and Webhook functionalities, built using the official Convex component architecture pattern.

First, install the necessary package:

npm install @dodopayments/convex

Here's how you should structure your response:

1. Ask the user which functionalities they want to integrate.

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

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

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

If Checkout Function is selected:

Purpose: This function handles different types of checkout flows and returns checkout URLs for programmatic handling.

Integration Steps:

Step 1: Add the component to your Convex configuration.

// convex/convex.config.ts
import { defineApp } from "convex/server";
import dodopayments from "@dodopayments/convex/convex.config";

const app = defineApp();
app.use(dodopayments);
export default app;

Step 2: Guide the user to set up environment variables in the Convex dashboard. Instruct them to open the dashboard by running:

npx convex dashboard

Then add the required environment variables (e.g., DODO_PAYMENTS_API_KEY, DODO_PAYMENTS_ENVIRONMENT, DODO_PAYMENTS_WEBHOOK_SECRET) in **Settings → Environment Variables**. Do not use .env files for backend functions.

DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_ENVIRONMENT=test_mode

Step 3: Create an internal query to fetch customers from your database.

// convex/customers.ts
import { internalQuery } from "./_generated/server";
import { v } from "convex/values";

// Internal query to fetch customer by auth ID
// Customize this based on your database schema and authentication provider
export const getByAuthId = internalQuery({
  args: { authId: v.string() },
  handler: async (ctx, { authId }) => {
    return await ctx.db
      .query("customers")
      .withIndex("by_auth_id", (q) => q.eq("authId", authId))
      .first();
  },
});

Step 4: Create your payment functions file.

// convex/dodo.ts
import { DodoPayments, DodoPaymentsClientConfig } from "@dodopayments/convex";
import { components } from "./_generated/api";
import { internal } from "./_generated/api";

export const dodo = new DodoPayments(components.dodopayments, {
  // This function maps your Convex user to a Dodo Payments customer
  // Customize it based on your authentication provider and customer database

  identify: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      return null; // User is not logged in
    }

    // Use ctx.runQuery() to lookup customer from your database
    const customer = await ctx.runQuery(internal.customers.getByAuthId, {
      authId: identity.subject,
    });

    if (!customer) {
      return null; // Customer not found in database
    }

    return {
      dodoCustomerId: customer.dodoCustomerId, // Replace customer.dodoCustomerId with your field storing Dodo Payments customer ID
    };
  },
  apiKey: process.env.DODO_PAYMENTS_API_KEY!,
  environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
} as DodoPaymentsClientConfig);

// Export the API methods for use in your app
export const { checkout, customerPortal } = dodo.api();

Step 5: Create actions that use the checkout function.

// convex/payments.ts
import { action } from "./_generated/server";
import { v } from "convex/values";
import { checkout } from "./dodo";

// Checkout session with full feature support
export const createCheckout = action({
  args: {
    product_cart: v.array(v.object({
      product_id: v.string(),
      quantity: v.number(),
    })),
    returnUrl: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    return await checkout(ctx, {
      payload: {
        product_cart: args.product_cart,
        return_url: args.returnUrl,
        billing_currency: "USD",
        feature_flags: {
          allow_discount_code: true,
        },
      },
    });
  },
});

Step 6: Use in your frontend.

// Your frontend component
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";

export function CheckoutButton() {
  const createCheckout = useAction(api.payments.createCheckout);

  const handleCheckout = async () => {
    const { checkout_url } = await createCheckout({
      product_cart: [{ product_id: "prod_123", quantity: 1 }],
    });
    window.location.href = checkout_url;
  };

  return <button onClick={handleCheckout}>Buy Now</button>;
}

Configuration Details:

- `checkout()`: Checkout session with full feature support using session checkout.
- Returns: `{"checkout_url": "https://checkout.dodopayments.com/..."}`

For complete API documentation, refer to:
- Checkout Sessions: https://docs.dodopayments.com/developer-resources/checkout-session
- One-time Payments: https://docs.dodopayments.com/api-reference/payments/post-payments
- Subscriptions: https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions

If Customer Portal Function is selected:

Purpose: This function allows customers to manage their subscriptions and payment methods.

Integration Steps:

Follow Steps 1-4 from the Checkout Function section, then:

Step 5: Create a customer portal action.

// convex/payments.ts (add to existing file)
import { action } from "./_generated/server";
import { v } from "convex/values";
import { customerPortal } from "./dodo";

export const getCustomerPortal = action({
  args: {
    send_email: v.optional(v.boolean()),
  },
  handler: async (ctx, args) => {
    return await customerPortal(ctx, args);
  },
});

Step 6: Use in your frontend.

// Your frontend component
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";

export function CustomerPortalButton() {
  const getPortal = useAction(api.payments.getCustomerPortal);

  const handlePortal = async () => {
    const { portal_url } = await getPortal({ send_email: false });
    window.location.href = portal_url;
  };

  return <button onClick={handlePortal}>Manage Subscription</button>;
}

Configuration Details:
- Requires authenticated user (via `identify` function).
- `send_email`: Optional boolean to send portal link via email.

If Webhook Handler is selected:

Purpose: This handler processes incoming webhook events from Dodo Payments, allowing your application to react to events like successful payments or subscription changes.

Integration Steps:

Step 1: Add the webhook secret to your environment variables in the Convex dashboard. You can open the dashboard by running:

Guide the user to open the Convex dashboard by running:

npx convex dashboard

In the dashboard, go to **Settings → Environment Variables** and add:

- `DODO_PAYMENTS_WEBHOOK_SECRET=whsec_...`

Do not use .env files for backend functions; always set secrets in the Convex dashboard.

Step 2: Create a file `convex/http.ts`:

// convex/http.ts
import { createDodoWebhookHandler } from "@dodopayments/convex";
import { httpRouter } from "convex/server";
import { internal } from "./_generated/api";

const http = httpRouter();

http.route({
  path: "/dodopayments-webhook",
  method: "POST",
  handler: createDodoWebhookHandler({
    // Handle successful payments
    onPaymentSucceeded: async (ctx, payload) => {
      console.log("🎉 Payment Succeeded!");
      // Use Convex context to persist payment data
      await ctx.runMutation(internal.webhooks.createPayment, {
        paymentId: payload.data.payment_id,
        businessId: payload.business_id,
        customerEmail: payload.data.customer.email,
        amount: payload.data.total_amount,
        currency: payload.data.currency,
        status: payload.data.status,
        webhookPayload: JSON.stringify(payload),
      });
    },

    // Handle subscription activation
    onSubscriptionActive: async (ctx, payload) => {
      console.log("🎉 Subscription Activated!");
      // Use Convex context to persist subscription data
      await ctx.runMutation(internal.webhooks.createSubscription, {
        subscriptionId: payload.data.subscription_id,
        businessId: payload.business_id,
        customerEmail: payload.data.customer.email,
        status: payload.data.status,
        webhookPayload: JSON.stringify(payload),
      });
    },
    // Add other event handlers as needed
  }),
});

export default http;

Supported Webhook Event Handlers:
- onPayload: Generic handler for all webhook events
- onPaymentSucceeded, onPaymentFailed, onPaymentProcessing, onPaymentCancelled
- onRefundSucceeded, onRefundFailed
- onDisputeOpened, onDisputeExpired, onDisputeAccepted, onDisputeCancelled, onDisputeChallenged, onDisputeWon, onDisputeLost
- onSubscriptionActive, onSubscriptionOnHold, onSubscriptionRenewed, onSubscriptionPlanChanged, onSubscriptionCancelled, onSubscriptionFailed, onSubscriptionExpired, onSubscriptionUpdated
- onLicenseKeyCreated
- onAbandonedCheckoutDetected, onAbandonedCheckoutRecovered
- onDunningStarted, onDunningRecovered
- onCreditAdded, onCreditDeducted, onCreditExpired, onCreditRolledOver, onCreditRolloverForfeited, onCreditOverageCharged, onCreditManualAdjustment, onCreditBalanceLow

Note: Make sure to define the corresponding database mutations in your Convex backend for each webhook event you want to handle. For example, create a `createPayment` mutation to record successful payments or a `createSubscription` mutation to manage subscription state.

Now, you can set the webhook endpoint URL in your Dodo Payments dashboard to `https://<your-convex-deployment-url>/dodopayments-webhook`.

Environment Variable Setup:

Set up the following environment variables in your Convex dashboard (Settings → Environment Variables). You can open the dashboard by running:

npx convex dashboard

Set:

- `DODO_PAYMENTS_API_KEY=your-api-key`
- `DODO_PAYMENTS_ENVIRONMENT=test_mode`
- `DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret`

Usage in your component configuration:

apiKey: process.env.DODO_PAYMENTS_API_KEY!
environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode"

Important: Never commit sensitive environment variables directly into your code. Always use Convex environment variables for all sensitive information.

If the user needs assistance setting up environment variables or deployment, ask them about their specific setup and provide guidance accordingly.

Run `npx convex dev` after setting up the component to generate the necessary types.

版本与发布记录

@dodopayments/convex 共发布 17 个版本,首次发布于 2025/09/26;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.16latest2026/11/0310 天前
0.2.152026/08/242 个月前
0.2.142026/08/152 个月前
0.2.132026/07/193 个月前
0.2.122026/05/185 个月前
0.2.112026/04/216 个月前

关于 @dodopayments/convex 的常见问题

如何安装 @dodopayments/convex?

在项目目录运行 npm install @dodopayments/convex,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:zod(^3.25.0 || ^4.0.0)、convex(^1.26.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dodopayments/convex 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dodopayments/convex 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@dodopayments/convex 可以商用吗?

@dodopayments/convex 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@dodopayments/convex 的下载量有多少?

根据 npm 官方下载统计,@dodopayments/convex 在 2026/10/13 – 2026/11/11 这 30 天内被下载 25,266 次,日均约 842 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dodopayments/convex 还在维护吗?

最新版本 0.2.16 发布于 2026/11/03(10 天前);至今共发布 17 个版本,其中过去 12 个月发布了 11 个;首次发布于 2025/09/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。