---
name: dodopayments
description: Use when building payment integrations, managing subscriptions,
  handling billing workflows, creating checkout experiences, or processing
  payments for SaaS, digital products, and AI applications. Agents should reach
  for this skill when users request payment processing, subscription management,
  webhook setup, customer billing, refunds, or any payment-related
  functionality.
metadata:
  mintlify-proj: dodopayments
  version: "1.0"
---

# Dodo Payments Skill

## Product Summary

Dodo Payments is a Merchant of Record (MOR) platform for SaaS, AI, and digital products. It handles payments, tax, billing, and compliance across 220+ countries. Agents use Dodo Payments to create checkout sessions, manage subscriptions, process refunds, handle webhooks, and build billing workflows via REST APIs and official SDKs (TypeScript, Python, Go, PHP, Java, Kotlin, C#, Ruby, Rust).

**Key files and commands:**
- API base URLs: `https://test.dodopayments.com` (test mode), `https://live.dodopayments.com` (live mode)
- Environment variable: `DODO_PAYMENTS_API_KEY` (Bearer token authentication)
- Webhook secret: `DODO_PAYMENTS_WEBHOOK_KEY` (for signature verification)
- SDKs: `npm install dodopayments` (Node.js), `pip install dodopayments` (Python), `go get github.com/dodopayments/dodopayments-go` (Go)
- Primary docs: https://docs.dodopayments.com

## When to Use

Reach for this skill when:
- **Creating checkout flows**: User wants to accept one-time payments, subscriptions, or usage-based billing
- **Managing subscriptions**: User needs to create, upgrade, downgrade, or cancel recurring billing
- **Handling webhooks**: User needs to listen for payment events (succeeded, failed, refunded, etc.)
- **Processing refunds**: User wants to issue refunds or handle chargebacks
- **Building customer portals**: User needs customers to manage their subscriptions and billing
- **Metering usage**: User wants to track and bill based on consumption (API calls, tokens, etc.)
- **Managing products**: User needs to create, update, or archive products with pricing
- **Handling payment failures**: User needs to retry failed payments or notify customers
- **Integrating with frameworks**: User is building with Next.js, Express, FastAPI, or other frameworks
- **Testing payments**: User needs to test in test mode before going live

## Quick Reference

### Authentication
Always include API key in Authorization header:
```
Authorization: Bearer dodo_test_... (test mode) or dodo_live_... (live mode)
```

### Core Endpoints
| Resource | Method | Endpoint | Purpose |
|----------|--------|----------|---------|
| Checkout Sessions | POST | `/checkouts` | Create a hosted checkout |
| Payments | GET | `/payments` | List or retrieve payments |
| Subscriptions | POST | `/subscriptions` | Create a subscription |
| Subscriptions | PATCH | `/subscriptions/{id}` | Update subscription (pause, resume, change plan) |
| Refunds | POST | `/refunds` | Issue a refund |
| Customers | POST | `/customers` | Create a customer |
| Products | POST | `/products` | Create a product |
| Webhooks | POST | `/webhooks` | Register a webhook endpoint |

### Billing Models
| Model | Use Case | Key Field |
|-------|----------|-----------|
| One-Time | Single charge for download, course, license | `type: "one_time_price"` |
| Subscription | Recurring billing with trials and proration | `type: "recurring_price"` with `payment_frequency_interval` |
| Usage-Based | Charge by metered consumption (API calls, tokens) | Create meter, ingest events, bill on usage |
| Credit-Based | Prepaid credits that deplete with usage | Create credit entitlement, track ledger |
| Seat-Based | Charge per user/seat with proration | Subscription with seat add-ons |

### SDK Initialization
```typescript
import DodoPayments from 'dodopayments';
const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // or 'live_mode'
  webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
});
```

### Webhook Verification
All SDKs provide `unwrap()` method to verify and parse webhooks:
```typescript
const event = client.webhooks.unwrap(rawBody, {
  headers: {
    'webhook-id': req.headers['webhook-id'],
    'webhook-signature': req.headers['webhook-signature'],
    'webhook-timestamp': req.headers['webhook-timestamp'],
  },
});
```

## Decision Guidance

### When to Use Checkout Sessions vs Payment Links

| Scenario | Use Checkout Sessions | Use Payment Links |
|----------|----------------------|-------------------|
| Dynamic pricing per customer | ✓ | ✗ |
| Pre-fill customer details from your system | ✓ | ✓ (via query params) |
| No code required | ✗ | ✓ |
| Shareable URL for multiple customers | ✗ | ✓ |
| Programmatic control from backend | ✓ | ✗ |
| One-time use per session | ✓ | ✗ (reusable) |

### When to Use Subscriptions vs One-Time Payments

| Scenario | Subscriptions | One-Time |
|----------|---------------|----------|
| Recurring revenue (SaaS, memberships) | ✓ | ✗ |
| Single purchase (course, ebook, license) | ✗ | ✓ |
| Trials and onboarding | ✓ | ✗ |
| Plan upgrades/downgrades | ✓ | ✗ |
| Usage-based billing | ✓ (with meters) | ✗ |

### When to Use Webhooks vs Polling

| Scenario | Webhooks | Polling |
|----------|----------|---------|
| Real-time fulfillment (grant access immediately) | ✓ | ✗ |
| Batch processing (daily reconciliation) | ✗ | ✓ |
| Reliability critical (must not miss events) | ✓ | ✗ |
| Low-frequency events | ✓ | ✗ |
| High-volume events (>1000/min) | ✓ | ✗ |

## Workflow

### 1. Set Up Authentication
- Generate API key in dashboard (Developer → API Keys)
- Store in `DODO_PAYMENTS_API_KEY` environment variable
- Choose test mode for development, live mode for production
- Test mode key starts with `dodo_test_`, live mode with `dodo_live_`

### 2. Create a Product
- Define pricing model: one-time, subscription, or usage-based
- Set price, currency, and optional trial (for subscriptions)
- Add product images and description
- Attach entitlements (license keys, digital files, feature flags)
- Note the `product_id` for checkout sessions

### 3. Create a Checkout Session
- Call `POST /checkouts` with product cart, customer email, and return URL
- Receive `checkout_url` (valid for 24 hours, one-time use)
- Redirect customer to `checkout_url`
- Customer completes payment and is redirected to `return_url`

### 4. Set Up Webhooks
- Create endpoint in dashboard (Developer → Webhooks)
- Copy webhook signing secret to `DODO_PAYMENTS_WEBHOOK_KEY`
- Select events to receive (payment.succeeded, subscription.active, etc.)
- Implement webhook handler that verifies signature and processes events
- Return `200` status immediately, process asynchronously

### 5. Handle Payment Events
- Listen for `payment.succeeded` to fulfill orders
- Listen for `payment.failed` to notify customer
- Listen for `subscription.active` to activate recurring billing
- Use webhook `webhook-id` header for idempotency (store processed IDs)

### 6. Manage Subscriptions
- Create subscription via checkout or API
- Listen for `subscription.active`, `subscription.renewed`, `subscription.cancelled`
- Update subscription with `PATCH /subscriptions/{id}` (pause, resume, change plan)
- Handle proration automatically on plan changes

### 7. Test Before Going Live
- Use test mode API key and test mode URLs
- Test cards: `4242 4242 4242 4242` (success), `4000 0000 0000 0002` (decline)
- Verify webhooks with dashboard testing tab
- Run account verification before switching to live mode

## Common Gotchas

- **Checkout URL expires**: Each `checkout_url` is single-use and expires after 24 hours (or 15 minutes with `confirm: true`). Create a new session for each attempt.
- **Webhook signature verification required**: Always verify `webhook-signature` header. Never trust webhook payloads without verification.
- **Idempotency critical**: Webhooks may retry and deliver the same event multiple times. Store `webhook-id` to detect duplicates.
- **Subscription minimum price**: Non-zero subscription prices must be ≥$1.00 USD (or equivalent in other currencies). $0 subscriptions are allowed but require no card.
- **Pricing model immutable**: Cannot change a product from one-time to subscription. Create a new product instead.
- **Test mode isolation**: Test mode API keys only work with `test.dodopayments.com`. Live mode keys only work with `live.dodopayments.com`.
- **Billing address required**: Pass `billing_address.country` when creating checkout to ensure correct currency and tax. Without it, Adaptive Currency guesses from IP.
- **Webhook timeout 30 seconds**: Return `200` immediately, process events asynchronously. Long-running handlers cause retries.
- **Rate limits apply**: Default tier: 40 req/sec burst, 240 req/min sustained. Implement exponential backoff on `429` responses.
- **Refunds are final**: Refunding a subscription payment cancels the subscription immediately. Cannot undo.
- **Discount codes stack**: Up to 20 codes per checkout. Percentage and flat-amount codes can combine.
- **Metadata is custom**: Use `metadata_*` fields to store your internal IDs for reconciliation. Not indexed for search.

## Verification Checklist

Before submitting work with Dodo Payments integration:

- [ ] API key is stored in environment variable, not hardcoded
- [ ] Webhook secret is stored securely and used for signature verification
- [ ] Webhook handler returns `200` status immediately, processes asynchronously
- [ ] Webhook handler implements idempotency check using `webhook-id` header
- [ ] Checkout session is created fresh for each payment attempt (not reused)
- [ ] `billing_address.country` is passed to ensure correct currency/tax
- [ ] Subscription products have price ≥$1.00 (or $0 if card-optional)
- [ ] Payment success is triggered by `payment.succeeded` webhook, not browser redirect
- [ ] Refund logic checks payment status before issuing refund
- [ ] Test mode is used during development, live mode only after verification
- [ ] Error handling branches on error `code`, not `message`
- [ ] Rate limit headers (`X-RateLimit-*`) are checked and exponential backoff implemented
- [ ] Webhook endpoint is HTTPS only (HTTP rejected)
- [ ] All required fields are present in API requests (check error codes for missing fields)
- [ ] Subscription plan changes use `PATCH /subscriptions/{id}` with proration settings

## Resources

**Comprehensive navigation:** https://docs.dodopayments.com/llms.txt

**Critical documentation pages:**
1. [Integration Guide](https://docs.dodopayments.com/developer-resources/integration-guide) — Start here for checkout sessions, payment links, and webhooks
2. [API Reference](https://docs.dodopayments.com/api-reference/introduction) — Complete endpoint documentation, authentication, error codes
3. [Webhook Guide](https://docs.dodopayments.com/developer-resources/webhooks) — Webhook setup, verification, testing, and event catalog

---

> For additional documentation and navigation, see: https://docs.dodopayments.com/llms.txt