dodo-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Dodo Payments Integration Guide

Dodo Payments 集成指南

Always consult docs.dodopayments.com for the latest API reference and code examples.
Dodo Payments is the all-in-one engine to launch, scale, and monetize worldwide. Designed for SaaS and AI products, it handles payments, billing, subscriptions, and distribution without extra engineering.

请始终参考docs.dodopayments.com获取最新的API参考文档和代码示例。
Dodo Payments 是一款一站式引擎,助力全球范围内的产品上线、规模化运营与变现。专为SaaS和AI产品设计,无需额外工程投入即可处理支付、计费、订阅与分发事宜。

Quick Reference

快速参考

Environment Variables

环境变量

  • DODO_PAYMENTS_API_KEY
    - Your API key from the dashboard
  • DODO_PAYMENTS_WEBHOOK_SECRET
    - Webhook signing secret for verification
  • DODO_PAYMENTS_API_KEY
    - 从控制台获取的API密钥
  • DODO_PAYMENTS_WEBHOOK_SECRET
    - 用于验证的Webhook签名密钥

API Environments

API环境

  • Live Mode:
    https://api.dodopayments.com
    (default)
  • Test Mode:
    https://api.dodopayments.com
    with
    environment: 'test_mode'
  • 生产模式
    https://api.dodopayments.com
    (默认)
  • 测试模式
    https://api.dodopayments.com
    ,需设置
    environment: 'test_mode'

Dashboard URLs

控制台链接

  • Main Dashboard: app.dodopayments.com
  • API Keys: Dashboard → Developer → API
  • Webhooks: Dashboard → Developer → Webhooks
  • Products: Dashboard → Products

  • 主控制台app.dodopayments.com
  • API密钥:控制台 → 开发者 → API
  • Webhook:控制台 → 开发者 → Webhooks
  • 产品:控制台 → 产品

SDK Installation

SDK安装

TypeScript/JavaScript

TypeScript/JavaScript

bash
npm install dodopayments
bash
npm install dodopayments

or

or

yarn add dodopayments
yarn add dodopayments

or

or

pnpm add dodopayments

```typescript
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'live_mode', // or 'test_mode'
});
pnpm add dodopayments

```typescript
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'live_mode', // or 'test_mode'
});

Python

Python

bash
pip install dodopayments
python
from dodopayments import DodoPayments

client = DodoPayments(bearer_token=os.environ["DODO_PAYMENTS_API_KEY"])
bash
pip install dodopayments
python
from dodopayments import DodoPayments

client = DodoPayments(bearer_token=os.environ["DODO_PAYMENTS_API_KEY"])

Go

Go

bash
go get github.com/dodopayments/dodopayments-go
go
import "github.com/dodopayments/dodopayments-go"

client := dodopayments.NewClient(
    option.WithBearerToken(os.Getenv("DODO_PAYMENTS_API_KEY")),
)
bash
go get github.com/dodopayments/dodopayments-go
go
import "github.com/dodopayments/dodopayments-go"

client := dodopayments.NewClient(
    option.WithBearerToken(os.Getenv("DODO_PAYMENTS_API_KEY")),
)

PHP

PHP

bash
composer require dodopayments/client
php
use Dodopayments\Client;

$client = new Client(bearerToken: getenv('DODO_PAYMENTS_API_KEY'));

bash
composer require dodopayments/client
php
use Dodopayments\Client;

$client = new Client(bearerToken: getenv('DODO_PAYMENTS_API_KEY'));

Core Concepts

核心概念

Products

产品

Products are the items you sell. Create them in the dashboard or via API:
  • One-time: Single purchase products
  • Subscription: Recurring billing products
产品是您销售的商品。可在控制台或通过API创建:
  • 一次性产品:单次购买的产品
  • 订阅产品:定期计费的产品

Checkout Sessions

结账会话

The primary way to collect payments. Create a checkout session and redirect customers:
typescript
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_xxxxx', quantity: 1 }
  ],
  customer: {
    email: 'customer@example.com',
    name: 'John Doe',
  },
  return_url: 'https://yoursite.com/success',
});

// Redirect customer to: session.checkout_url
这是收取付款的主要方式。创建结账会话并将客户重定向至对应页面:
typescript
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_xxxxx', quantity: 1 }
  ],
  customer: {
    email: 'customer@example.com',
    name: 'John Doe',
  },
  return_url: 'https://yoursite.com/success',
});

// 重定向客户至:session.checkout_url

Webhooks

Webhook

Listen to events for real-time updates:
  • payment.succeeded
    - Payment completed
  • payment.failed
    - Payment failed
  • subscription.active
    - Subscription activated
  • subscription.cancelled
    - Subscription cancelled
  • refund.succeeded
    - Refund processed
  • dispute.opened
    - Dispute received
  • license_key.created
    - License key generated

监听事件以获取实时更新:
  • payment.succeeded
    - 付款完成
  • payment.failed
    - 付款失败
  • subscription.active
    - 订阅已激活
  • subscription.cancelled
    - 订阅已取消
  • refund.succeeded
    - 退款已处理
  • dispute.opened
    - 收到争议请求
  • license_key.created
    - 生成许可证密钥

Common Integration Patterns

常见集成模式

One-Time Payment Flow

一次性付款流程

  1. Create product in dashboard
  2. Create checkout session with product ID
  3. Redirect customer to checkout URL
  4. Handle
    payment.succeeded
    webhook
  5. Fulfill order / grant access
typescript
// Create checkout for one-time payment
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_one_time_product', quantity: 1 }],
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/success',
});
  1. 在控制台创建产品
  2. 使用产品ID创建结账会话
  3. 将客户重定向至结账URL
  4. 处理
    payment.succeeded
    Webhook事件
  5. 履行订单 / 授予访问权限
typescript
// 创建一次性付款的结账会话
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_one_time_product', quantity: 1 }],
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/success',
});

Subscription Flow

订阅流程

  1. Create subscription product in dashboard
  2. Create checkout session
  3. Handle
    subscription.active
    webhook to grant access
  4. Handle
    subscription.cancelled
    to revoke access
typescript
// Create checkout for subscription
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_monthly_subscription', quantity: 1 }],
  subscription_data: { trial_period_days: 14 }, // Optional trial
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/success',
});
  1. 在控制台创建订阅产品
  2. 创建结账会话
  3. 处理
    subscription.active
    Webhook事件以授予访问权限
  4. 处理
    subscription.cancelled
    事件以收回访问权限
typescript
// 创建订阅的结账会话
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_monthly_subscription', quantity: 1 }],
  subscription_data: { trial_period_days: 14 }, // 可选试用期
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/success',
});

Webhook Verification

Webhook验证

Always verify webhook signatures:
typescript
import crypto from 'crypto';

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

务必验证Webhook签名:
typescript
import crypto from 'crypto';

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

API Key Management

API密钥管理

Generation

生成步骤

  1. Navigate to Dashboard → Developer → API
  2. Click "Create API Key"
  3. Copy and securely store the key
  1. 导航至控制台 → 开发者 → API
  2. 点击"创建API密钥"
  3. 复制并安全存储密钥

Security Best Practices

安全最佳实践

  • Never expose API keys in client-side code
  • Use environment variables
  • Rotate keys periodically
  • Use test mode keys for development

  • 切勿在客户端代码中暴露API密钥
  • 使用环境变量存储密钥
  • 定期轮换密钥
  • 开发时使用测试模式密钥

Customer Portal

客户门户

Allow customers to manage their subscriptions:
typescript
const portal = await client.customers.createPortalSession({
  customer_id: 'cust_xxxxx',
  return_url: 'https://yoursite.com/account',
});

// Redirect to: portal.url

允许客户管理他们的订阅:
typescript
const portal = await client.customers.createPortalSession({
  customer_id: 'cust_xxxxx',
  return_url: 'https://yoursite.com/account',
});

// 重定向至:portal.url

Error Handling

错误处理

Handle API errors gracefully:
typescript
try {
  const session = await client.checkoutSessions.create({...});
} catch (error) {
  if (error.status === 400) {
    // Invalid request - check parameters
  } else if (error.status === 401) {
    // Invalid API key
  } else if (error.status === 429) {
    // Rate limited - implement backoff
  }
}

优雅地处理API错误:
typescript
try {
  const session = await client.checkoutSessions.create({...});
} catch (error) {
  if (error.status === 400) {
    // 请求无效 - 检查参数
  } else if (error.status === 401) {
    // API密钥无效
  } else if (error.status === 429) {
    // 请求超限 - 实现退避机制
  }
}

Testing

测试

Test Mode

测试模式

  • Use test API keys (start with
    sk_test_
    )
  • Test webhooks with dashboard tools
  • Use test card numbers:
    • 4242 4242 4242 4242
      - Success
    • 4000 0000 0000 0002
      - Decline
  • 使用测试API密钥(以
    sk_test_
    开头)
  • 使用控制台工具测试Webhook
  • 使用测试卡号:
    • 4242 4242 4242 4242
      - 付款成功
    • 4000 0000 0000 0002
      - 付款被拒绝

Local Development

本地开发

Use ngrok or similar for webhook testing:
bash
ngrok http 3000
Then configure the ngrok URL as your webhook endpoint in the dashboard.

使用ngrok或类似工具进行Webhook测试:
bash
ngrok http 3000
然后在控制台中将ngrok URL配置为您的Webhook端点。

Framework Integration

框架集成

Next.js

Next.js

Use API routes for server-side operations:
typescript
// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
});

export async function POST(req: Request) {
  const { productId, email } = await req.json();
  
  const session = await client.checkoutSessions.create({
    product_cart: [{ product_id: productId, quantity: 1 }],
    customer: { email },
    return_url: `${process.env.NEXT_PUBLIC_URL}/success`,
  });

  return NextResponse.json({ url: session.checkout_url });
}
使用API路由处理服务器端操作:
typescript
// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
});

export async function POST(req: Request) {
  const { productId, email } = await req.json();
  
  const session = await client.checkoutSessions.create({
    product_cart: [{ product_id: productId, quantity: 1 }],
    customer: { email },
    return_url: `${process.env.NEXT_PUBLIC_URL}/success`,
  });

  return NextResponse.json({ url: session.checkout_url });
}

Express.js

Express.js

typescript
import express from 'express';
import DodoPayments from 'dodopayments';

const app = express();
const client = new DodoPayments({ bearerToken: process.env.DODO_PAYMENTS_API_KEY! });

app.post('/create-checkout', async (req, res) => {
  const session = await client.checkoutSessions.create({
    product_cart: [{ product_id: req.body.productId, quantity: 1 }],
    customer: { email: req.body.email },
    return_url: 'https://yoursite.com/success',
  });
  res.json({ url: session.checkout_url });
});

typescript
import express from 'express';
import DodoPayments from 'dodopayments';

const app = express();
const client = new DodoPayments({ bearerToken: process.env.DODO_PAYMENTS_API_KEY! });

app.post('/create-checkout', async (req, res) => {
  const session = await client.checkoutSessions.create({
    product_cart: [{ product_id: req.body.productId, quantity: 1 }],
    customer: { email: req.body.email },
    return_url: 'https://yoursite.com/success',
  });
  res.json({ url: session.checkout_url });
});

Resources

资源