Checkout Handler
将 Dodo Payments 结账集成到你的 Tanstack 应用。
Customer Portal
允许客户管理订阅和信息。
Webhooks
接收并处理 Dodo Payments webhook 事件。
安装
1
Install the package
在项目根目录运行以下命令:
npm install @dodopayments/tanstack
2
Set up environment variables
在项目根目录创建一个
.env 文件:DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
DODO_PAYMENTS_RETURN_URL=your-return-url
DODO_PAYMENTS_ENVIRONMENT="test_mode" or "live_mode"
切勿将
.env 文件或密钥提交到版本控制。路由处理程序示例
所有示例均假设你正在使用 Tanstack App Router。
- Checkout Handler
- Customer Portal Handler
- Webhook Handler
使用此处理程序将 Dodo Payments 结账集成到你的 Tanstack 应用。支持静态(GET)、动态(POST)和会话(POST)支付流程。
// src/routes/api/checkout.ts
import { Checkout } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute("/api/checkout")
.methods({
GET: async ({ request }) => {
return Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
type: "static", // optional, defaults to 'static'
})(request)
},
POST: async ({ request }) => {
return Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
type: "session", // or "dynamic" for dynamic link
})(request)
}
})
curl --request GET \
--url 'https://example.com/api/checkout?productId=pdt_fqJhl7pxKWiLhwQR042rh' \
--header 'User-Agent: insomnia/11.2.0' \
--cookie mode=test
curl --request POST \
--url https://example.com/api/checkout \
--header 'Content-Type: application/json' \
--header 'User-Agent: insomnia/11.2.0' \
--cookie mode=test \
--data '{
"billing": {
"city": "Texas",
"country": "US",
"state": "Texas",
"street": "56, hhh",
"zipcode": "560000"
},
"customer": {
"email": "test@example.com",
"name": "test"
},
"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
}'
curl --request POST \
--url https://example.com/api/checkout \
--header 'Content-Type: application/json' \
--header 'User-Agent: insomnia/11.2.0' \
--cookie mode=test \
--data '{
"product_cart": [
{
"product_id": "pdt_QMDuvLkbVzCRWRQjLNcs",
"quantity": 1
}
],
"customer": {
"email": "test@example.com",
"name": "test"
},
"return_url": "https://example.com/success"
}'
使用此处理程序允许客户通过 Dodo Payments 客户门户管理其订阅和信息。
// src/routes/api/customer-portal.ts
import { CustomerPortal } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute('/api/customer-portal')
.methods({
GET: async ({ request }) => {
return CustomerPortal({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
})(request)
}
})
curl --request GET \
--url 'https://example.com/api/customer-portal?customer_id=cus_9VuW4K7O3GHwasENg31m&send_email=true' \
--header 'User-Agent: insomnia/11.2.0' \
--cookie mode=test
使用此处理程序在你的 Tanstack 应用中安全地接收和处理 Dodo Payments webhook 事件。
// src/routes/api/webhook.ts
import { Webhooks } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute('/api/webhook')
.methods({
POST: async ({ request }) => {
return Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
onPayload: async (payload) => {
console.log(payload)
}
})(request)
}
})
结账路由处理程序
Dodo Payments 支持三种类型的支付流程来将支付集成到你的网站中,此适配器支持所有类型的支付流程。
- 静态支付链接: 可即时分享的 URL,用于快速、无代码的支付收集。
- 动态支付链接: 使用 API 或 SDK 程序化生成带有自定义详细信息的支付链接。
- 结账会话: 创建安全、可自定义的结账体验,预配置产品购物车和客户详细信息。
Static Checkout (GET)
Static Checkout (GET)
支持的 Query Parameters
string
必填
产品标识符(例如
?productId=pdt_nZuwz45WAs64n3l07zpQR)。integer
产品数量。
string
客户的全名。
string
客户的名字。
string
客户的姓氏。
string
客户的电子邮件地址。
string
客户所在的国家/地区。
string
客户的地址行。
string
客户所在的城市。
string
客户所在的州/省。
string
客户的邮政编码。
boolean
禁用全名字段。
boolean
禁用名字字段。
boolean
禁用姓氏字段。
boolean
禁用电子邮件字段。
boolean
禁用国家/地区字段。
boolean
禁用地址行字段。
boolean
禁用城市字段。
boolean
禁用州/省字段。
boolean
禁用邮政编码字段。
string
指定支付货币(例如
USD)。boolean
显示货币选择器。
number
固定收取的金额,单位为主要货币单位(例如,
12.5 表示 12.50 美元)。仅适用于随心付费产品;如果金额低于产品的最低价格,则会忽略此参数。boolean
显示折扣字段。
string
任何以
metadata_ 开头的查询参数都会作为 metadata 传递。如果
productId 缺失,处理程序将返回 400 响应。无效的查询参数也会导致 400 响应。响应格式
静态结账返回一个包含结账 URL 的 JSON 响应:{
"checkout_url": "https://checkout.dodopayments.com/..."
}
Dynamic Checkout (POST)
Dynamic Checkout (POST)
- 在 POST 请求中以 JSON 正文发送参数。
- 同时支持一次性和定期付款。
- 有关支持的 POST 请求字段的完整列表,请参阅:
Dynamic Checkout 代理已弃用的
POST /payments 和 POST /subscriptions endpoints。它会继续为现有集成提供支持,但新集成应使用下方的 Checkout Sessions。Response Format
Dynamic checkout 返回包含 checkout URL 的 JSON response:{
"checkout_url": "https://checkout.dodopayments.com/..."
}
Checkout Sessions (POST)
Checkout Sessions (POST)
Checkout sessions 提供更安全的托管式 checkout experience,可为一次性购买和订阅处理完整的 payment flow,同时提供全面的 customization control。如需了解更多详情以及完整的 supported fields 列表,请参阅 Checkout Sessions Integration Guide。
Response Format
Checkout sessions 返回包含 checkout URL 的 JSON response:{
"checkout_url": "https://checkout.dodopayments.com/session/..."
}
Customer Portal Route Handler
Customer Portal Route Handler 让您能够将 Dodo Payments customer portal 无缝集成到您的 Tanstack application 中。Query Parameters
string
必填
门户 session 的 customer ID(例如
?customer_id=cus_123)。boolean
如果设置为
true,则会向 customer 发送包含门户链接的 email。如果缺少
customer_id,则返回 400。Webhook Route Handler
- Method: 仅支持 POST requests。其他 methods 返回 405。
- Signature Verification: 使用
webhookKey验证 webhook signature。验证失败时返回 401。 - Payload Validation: 使用 Zod 进行验证。payload 无效时返回 400。
- Error Handling:
- 401:Invalid signature
- 400:Invalid payload
- 500:verification 期间发生 internal error
- Event Routing: 根据 payload type 调用相应的 event handler。
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>;
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>;
onCreditManualAdjustment?: (payload: WebhookPayload) => Promise<void>;
onCreditBalanceLow?: (payload: WebhookPayload) => Promise<void>;
Prompt for LLM
You are an expert Tanstack developer assistant. Your task is to guide a user through integrating the @dodopayments/tanstack adapter into their existing Tanstack project.
The @dodopayments/tanstack adapter provides route handlers for Dodo Payments' Checkout, Customer Portal, and Webhook functionalities, designed for the Tanstack App Router.
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/tanstack
Here's how you should structure your response:
Ask the user which functionalities they want to integrate.
"Which parts of the @dodopayments/tanstack 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 redirects users to the Dodo Payments checkout page.
File Creation: Create a new file at app/checkout/route.ts in your Tanstack project.
Code Snippet:
// src/routes/api/checkout.ts
import { Checkout } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute("/api/checkout")
.methods({
GET: async ({ request }) => {
return Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
type: "static", // optional, defaults to 'static'
})(request)
},
POST: async ({ request }) => {
return Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
type: "session", // or "dynamic" for dynamic link
})(request)
}
})
Configuration & Usage:
bearerToken: Your Dodo Payments API key. It's recommended to set this via the DODO_PAYMENTS_API_KEY environment variable.
returnUrl: (Optional) The URL to redirect the user to after a successful checkout.
environment: (Optional) Set to "test_mode" for testing, or omit/set to "live_mode" for production.
type: (Optional) Set to "static" for GET/static checkout, "dynamic" for POST/dynamic checkout, or "session" for POST/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)
Returns: {"checkout_url": "https://checkout.dodopayments.com/..."}
Dynamic Checkout (POST) - Returns JSON with checkout_url: Parameters are sent as a JSON body. Supports both one-time and recurring payments. Returns: {"checkout_url": "https://checkout.dodopayments.com/..."}. 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. 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 Route Handler is selected:
Purpose: This handler redirects authenticated users to their Dodo Payments customer portal.
File Creation: Create a new file at app/customer-portal/route.ts in your Tanstack project.
Code Snippet:
// src/routes/api/customer-portal.ts
import { CustomerPortal } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute('/api/customer-portal')
.methods({
GET: async ({ request }) => {
return CustomerPortal({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
})(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/api/webhook/dodo-payments/route.ts in your Tanstack project.
Code Snippet:
// src/routes/api/webhook.ts
import { Webhooks } from "@dodopayments/tanstack";
import { createServerFileRoute } from "@tanstack/react-start/server";
export const ServerRoute = createServerFileRoute('/api/webhook')
.methods({
POST: async ({ request }) => {
return Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
onPayload: async (payload) => {
console.log(payload)
}
})(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 the appropriate event handler based on the payload 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>
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>
onCreditManualAdjustment?: (payload: WebhookPayload) => Promise<void>
onCreditBalanceLow?: (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 Tanstack 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).
RETURN_URL: (Optional) The URL to redirect to after a successful checkout (for Checkout handler).
DODO_PAYMENTS_WEBHOOK_SECRET: Your Dodo Payments Webhook Secret (required for Webhook handler).
Example .env file:
DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
DODO_PAYMENTS_RETURN_URL=your-return-url
DODO_PAYMENTS_ENVIRONMENT="test_mode" or "live_mode"
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