checkout-integration
Guide for creating checkout sessions and payment flows with Dodo Payments - one-time, subscriptions, and overlay checkout.
What this skill does
# Dodo Payments Checkout Integration
**Reference: [docs.dodopayments.com/developer-resources/integration-guide](https://docs.dodopayments.com/developer-resources/integration-guide)**
Create seamless payment experiences with hosted checkout pages or overlay checkout modals.
---
## Checkout Methods
| Method | Best For | Integration |
|--------|----------|-------------|
| **Hosted Checkout** | Simple integration, full-page redirect | Server-side SDK |
| **Overlay Checkout** | Seamless UX, stays on your site | JavaScript SDK |
| **Payment Links** | No-code, shareable links | Dashboard |
---
## Hosted Checkout
### Basic Implementation
```typescript
import DodoPayments from 'dodopayments';
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
});
// Create checkout session
const session = await client.checkoutSessions.create({
product_cart: [
{ product_id: 'prod_xxxxx', quantity: 1 }
],
customer: {
email: '[email protected]',
name: 'John Doe',
},
return_url: 'https://yoursite.com/checkout/success',
});
// Redirect customer to checkout
// session.checkout_url
```
### With Multiple Products
```typescript
const session = await client.checkoutSessions.create({
product_cart: [
{ product_id: 'prod_item_1', quantity: 2 },
{ product_id: 'prod_item_2', quantity: 1 },
],
customer: {
email: '[email protected]',
},
return_url: 'https://yoursite.com/success',
});
```
### With Customer ID (Existing Customer)
```typescript
const session = await client.checkoutSessions.create({
product_cart: [
{ product_id: 'prod_xxxxx', quantity: 1 }
],
customer_id: 'cust_existing_customer',
return_url: 'https://yoursite.com/success',
});
```
### With Metadata
```typescript
const session = await client.checkoutSessions.create({
product_cart: [
{ product_id: 'prod_xxxxx', quantity: 1 }
],
customer: {
email: '[email protected]',
},
metadata: {
order_id: 'order_12345',
referral_code: 'FRIEND20',
user_id: 'internal_user_id',
},
return_url: 'https://yoursite.com/success',
});
```
---
## Next.js Implementation
### API Route
```typescript
// app/api/checkout/route.ts
import { NextRequest, NextResponse } from 'next/server';
import DodoPayments from 'dodopayments';
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
});
export async function POST(req: NextRequest) {
try {
const { productId, quantity = 1, email, name, metadata } = await req.json();
if (!productId || !email) {
return NextResponse.json(
{ error: 'Missing required fields' },
{ status: 400 }
);
}
const session = await client.checkoutSessions.create({
product_cart: [{ product_id: productId, quantity }],
customer: { email, name },
metadata,
return_url: `${process.env.NEXT_PUBLIC_APP_URL}/checkout/success`,
});
return NextResponse.json({
checkoutUrl: session.checkout_url,
sessionId: session.checkout_session_id,
});
} catch (error: any) {
console.error('Checkout error:', error);
return NextResponse.json(
{ error: error.message || 'Failed to create checkout' },
{ status: 500 }
);
}
}
```
### Client Component
```typescript
// components/CheckoutButton.tsx
'use client';
import { useState } from 'react';
interface CheckoutButtonProps {
productId: string;
email: string;
name?: string;
children: React.ReactNode;
}
export function CheckoutButton({ productId, email, name, children }: CheckoutButtonProps) {
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId, email, name }),
});
const data = await response.json();
if (data.checkoutUrl) {
window.location.href = data.checkoutUrl;
} else {
throw new Error(data.error || 'Failed to create checkout');
}
} catch (error) {
console.error('Checkout error:', error);
alert('Failed to start checkout. Please try again.');
} finally {
setLoading(false);
}
};
return (
<button onClick={handleCheckout} disabled={loading}>
{loading ? 'Loading...' : children}
</button>
);
}
```
### Success Page
```typescript
// app/checkout/success/page.tsx
import { Suspense } from 'react';
function SuccessContent() {
return (
<div className="text-center py-20">
<h1 className="text-3xl font-bold">Payment Successful!</h1>
<p className="mt-4 text-gray-600">
Thank you for your purchase. You will receive a confirmation email shortly.
</p>
<a href="/" className="mt-8 inline-block text-blue-600 hover:underline">
Return to Home
</a>
</div>
);
}
export default function SuccessPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<SuccessContent />
</Suspense>
);
}
```
---
## Overlay Checkout
Embed checkout directly on your page without redirects.
### Installation
```bash
npm install @dodopayments/checkout
```
### Basic Usage
```typescript
import { DodoCheckout } from '@dodopayments/checkout';
// Initialize
const checkout = new DodoCheckout({
apiKey: 'your_publishable_key',
environment: 'live', // or 'test'
});
// Open overlay
checkout.open({
productId: 'prod_xxxxx',
customer: {
email: '[email protected]',
},
onSuccess: (result) => {
console.log('Payment successful:', result);
// Handle success
},
onClose: () => {
console.log('Checkout closed');
},
});
```
### React Component
```typescript
// components/OverlayCheckout.tsx
'use client';
import { useEffect, useRef } from 'react';
import { DodoCheckout } from '@dodopayments/checkout';
interface OverlayCheckoutProps {
productId: string;
email: string;
onSuccess?: (result: any) => void;
children: React.ReactNode;
}
export function OverlayCheckout({
productId,
email,
onSuccess,
children
}: OverlayCheckoutProps) {
const checkoutRef = useRef<DodoCheckout | null>(null);
useEffect(() => {
checkoutRef.current = new DodoCheckout({
apiKey: process.env.NEXT_PUBLIC_DODO_PUBLISHABLE_KEY!,
environment: process.env.NODE_ENV === 'production' ? 'live' : 'test',
});
return () => {
checkoutRef.current?.close();
};
}, []);
const handleClick = () => {
checkoutRef.current?.open({
productId,
customer: { email },
onSuccess: (result) => {
onSuccess?.(result);
// Optionally redirect
window.location.href = '/checkout/success';
},
onClose: () => {
console.log('Checkout closed');
},
});
};
return (
<button onClick={handleClick}>
{children}
</button>
);
}
```
### Customization
```typescript
checkout.open({
productId: 'prod_xxxxx',
customer: { email: '[email protected]' },
theme: {
primaryColor: '#0066FF',
backgroundColor: '#FFFFFF',
fontFamily: 'Inter, sans-serif',
},
locale: 'en',
});
```
---
## Express.js Implementation
```typescript
import express from 'express';
import DodoPayments from 'dodopayments';
const app = express();
app.use(express.json());
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
});
app.post('/api/create-checkout', async (req, res) => {
try {
const { productId, email, name, quantity = 1 } = req.body;
const session = await client.checkoutSessions.create({
product_cart: [{ product_id: productId, quantity }],
customer: { email, name },
return_url: `${process.env.APP_URL}/success`,
});
res.json({ checkoutUrl: session.checkout_url });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// Success page rRelated in Sales & CRM
process-mapper
IncludedUse when a BizOps lead, COO, or process-improvement owner needs to document an end-to-end business process (procurement, employee onboarding, incident handoff, customer-onboarding, claims adjudication) in BPMN-style notation, measure cycle times by stage, surface where work spends most of its time waiting vs. being worked, and quantify the gap between processing time and total elapsed time. Pairs Lean / Six Sigma / Theory-of-Constraints canon with deterministic stdlib-only Python tools to produce a process map, a ranked bottleneck list (with severity + root-cause hypothesis), and a cycle-time analysis (P50, P90, value-add ratio, Little's-Law throughput). Distinct from sales-pipeline, system-reliability (SLO), and strategic-OKR work — this is tactical process documentation for internal operations.
payment-integration
IncludedIntegrate payments with SePay (VietQR), Polar, Stripe, Paddle (MoR subscriptions), Creem.io (licensing). Checkout, webhooks, subscriptions, QR codes, multi-provider orders.
customer-success-manager
IncludedMonitors customer health, predicts churn risk, and identifies expansion opportunities using weighted scoring models for SaaS customer success
sales-engineer
IncludedAnalyzes RFP/RFI responses for coverage gaps, builds competitive feature comparison matrices, and plans proof-of-concept (POC) engagements for pre-sales engineering. Use when responding to RFPs, bids, or proposal requests; comparing product features against competitors; planning or scoring a customer POC or sales demo; preparing a technical proposal; or performing win/loss competitor analysis. Handles tasks described as 'RFP response', 'bid response', 'proposal response', 'competitor comparison', 'feature matrix', 'POC planning', 'sales demo prep', or 'pre-sales engineering'.
customer-success-manager
IncludedMonitors customer health, predicts churn risk, and identifies expansion opportunities using weighted scoring models for SaaS customer success
sales-engineer
IncludedAnalyzes RFP/RFI responses for coverage gaps, builds competitive feature comparison matrices, and plans proof-of-concept (POC) engagements for pre-sales engineering. Use when responding to RFPs, bids, or proposal requests; comparing product features against competitors; planning or scoring a customer POC or sales demo; preparing a technical proposal; or performing win/loss competitor analysis. Handles tasks described as 'RFP response', 'bid response', 'proposal response', 'competitor comparison', 'feature matrix', 'POC planning', 'sales demo prep', or 'pre-sales engineering'.