Dodo Payments
Dodo Payments component
git clone https://github.com/bijectionhq/dodo-payments.git
cd dodo-payments
git checkout 7f87230383f3c3bad91a82e26671e5d5fee32136
cd packages/convexBijection repository access is required. Request access.
Description
Dodo Payments component
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/dodo-payments. Based on dodopayments/dodo-adapters. License: GPL-3.0. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
[](https://badge.fury.io/js/@dodopayments%2Fconvex.svg)
Upstream overview
From the upstream package documentation.
The Dodo Payments Convex component integrates checkout sessions, customer portals, and webhook handling directly into Convex applications. It provides a complete billing solution with built-in webhook verification, customer identification mapping, and payment flow management. The component handles the complexity of payment processing while letting you focus on your business logic within Convex's serverless architecture.
Use cases
From the upstream package documentation.
- SaaS subscription billing - Handle recurring subscriptions, plan upgrades, and customer self-service portals for your AI or SaaS application
- One-time product sales - Create checkout flows for digital products, credits, or feature unlocks with automatic payment confirmation
- Usage-based billing - Process payments for API usage, compute credits, or consumption-based pricing models
- Multi-tenant billing - Manage separate billing for different organizations or workspaces within your application
- Payment webhook processing - Automatically sync payment status, subscription changes, and customer data to your Convex database
How it works
From the upstream package documentation.
The component follows Convex's component architecture pattern, requiring installation via app.use(dodopayments) in your convex.config.ts. You configure a DodoPayments instance with an identify function that maps your authenticated Convex users to Dodo Payments customers using internal queries.
Checkout and customer portal functionality is exposed through the dodo.api() methods, which you call from Convex actions. The checkout function accepts product carts and billing configuration, returning checkout URLs for frontend redirection. The customerPortal function generates self-service management links.
Webhook handling uses createDodoWebhookHandler in your http.ts file, providing event-specific handlers like onPaymentSucceeded and onSubscriptionActive. Each webhook handler receives Convex's ActionCtx, allowing you to use ctx.runMutation() to persist payment data directly to your database with automatic webhook signature verification.
Upstream package FAQ
Does Dodo Payments work with Convex's real-time features?
Yes, Dodo Payments integrates fully with Convex's reactive queries and subscriptions. Payment status changes, subscription updates, and billing events automatically trigger real-time updates to your application UI through Convex's built-in reactivity.
Can I customize the billing logic for AI applications?
Dodo Payments provides flexible usage tracking functions that you can customize for AI-specific billing patterns. You can track token consumption, API calls, model usage, or any custom metrics through configurable Convex mutations and automatic aggregation.
How does this handle PCI compliance for payment processing?
Dodo Payments handles PCI compliance by processing sensitive payment data on secure servers while exposing only safe operations through Convex actions. Your Convex database stores transaction metadata and billing information without touching raw payment card data.
What payment methods does the Convex integration support?
The Dodo Payments Convex package supports credit cards, ACH transfers, and digital wallet payments. All payment method management happens through Convex actions that return payment status and customer information to your database.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Dodo Payments with Bijection.
Read: https://bijection.com/components/dodo-payments/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from dodopayments/dodo-adapters, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
Dodo Payments Convex Component
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-keyDODO_PAYMENTS_ENVIRONMENT=test_modeDODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret(if using webhooks)
Note: Convex backend functions only read environment variables set in the Convex dashboard.
.envfiles 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",
[README truncated for prompt length]