Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
dodopayments avatar

Checkout Integration

  • 734 installs
  • 11 repo stars
  • Updated August 1, 2026
  • dodopayments/skills

checkout-integration is a Claude Code skill that adds one-time payments, subscriptions, and hosted or overlay checkout flows with Dodo Payments for developers who need production payment acceptance.

About

checkout-integration is a Claude Code skill guided by docs.dodopayments.com that implements Dodo Payments checkout sessions for one-time charges and subscriptions. The skill compares hosted checkout full-page redirects via the server-side SDK against overlay checkout modals that keep users on-site with JavaScript. Developers reach for checkout-integration when adding first payment acceptance, subscription billing, or an embedded checkout UX without building a custom processor integration from scratch. The guide references the official integration guide and maps each checkout method to the right client and server artifacts.

  • Three checkout methods: Hosted Checkout, Overlay Checkout, and no-code Payment Links
  • Server-side SDK for creating checkout sessions with product cart and customer data
  • JavaScript SDK support for seamless overlay modal experience
  • Full implementation examples for single-product and multi-product carts
  • Official reference to docs.dodopayments.com integration guide

Checkout Integration by the numbers

  • 734 all-time installs (skills.sh)
  • Ranked #510 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dodopayments/skills --skill checkout-integration

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs734
repo stars11
Security audit2 / 3 scanners passed
Last updatedAugust 1, 2026
Repositorydodopayments/skills

How do you integrate Dodo Payments checkout?

Quickly add one-time payments, subscriptions, and hosted or overlay checkout flows using Dodo Payments.

Who is it for?

Backend and full-stack developers adding Dodo Payments to a SaaS or storefront who want hosted or overlay checkout without custom payment UI.

Skip if: Projects already committed to Stripe, Paddle, or another processor where Dodo Payments is not the chosen billing provider.

When should I use this skill?

A developer asks to add Dodo Payments, create checkout sessions, enable subscriptions, or embed overlay checkout on an existing site.

What you get

Checkout session code, hosted redirect flow wiring, overlay checkout JavaScript integration, and subscription billing setup.

  • checkout session handlers
  • overlay embed code
  • subscription flow wiring

Files

SKILL.mdMarkdownGitHub ↗

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

MethodBest ForIntegration
Hosted CheckoutSimple integration, full-page redirectServer-side SDK
Overlay CheckoutSeamless UX, stays on your siteJavaScript SDK
Payment LinksNo-code, shareable linksDashboard

---

Hosted Checkout

Basic Implementation

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: 'customer@example.com',
    name: 'John Doe',
  },
  return_url: 'https://yoursite.com/checkout/success',
});

// Redirect customer to checkout
// session.checkout_url

With Multiple Products

const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_item_1', quantity: 2 },
    { product_id: 'prod_item_2', quantity: 1 },
  ],
  customer: {
    email: 'customer@example.com',
  },
  return_url: 'https://yoursite.com/success',
});

With Customer ID (Existing Customer)

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

const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_xxxxx', quantity: 1 }
  ],
  customer: {
    email: 'customer@example.com',
  },
  metadata: {
    order_id: 'order_12345',
    referral_code: 'FRIEND20',
    user_id: 'internal_user_id',
  },
  return_url: 'https://yoursite.com/success',
});

---

Next.js Implementation

API Route

// 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

// 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

// 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

npm install @dodopayments/checkout

Basic Usage

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: 'customer@example.com',
  },
  onSuccess: (result) => {
    console.log('Payment successful:', result);
    // Handle success
  },
  onClose: () => {
    console.log('Checkout closed');
  },
});

React Component

// 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

checkout.open({
  productId: 'prod_xxxxx',
  customer: { email: 'customer@example.com' },
  theme: {
    primaryColor: '#0066FF',
    backgroundColor: '#FFFFFF',
    fontFamily: 'Inter, sans-serif',
  },
  locale: 'en',
});

---

Express.js Implementation

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 route
app.get('/success', (req, res) => {
  res.send('Payment successful!');
});

---

Python Implementation

FastAPI

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from dodopayments import DodoPayments
import os

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

class CheckoutRequest(BaseModel):
    product_id: str
    email: str
    name: str = None
    quantity: int = 1

@app.post("/api/checkout")
async def create_checkout(request: CheckoutRequest):
    try:
        session = client.checkout_sessions.create(
            product_cart=[{
                "product_id": request.product_id,
                "quantity": request.quantity
            }],
            customer={
                "email": request.email,
                "name": request.name
            },
            return_url=f"{os.environ['APP_URL']}/success"
        )
        
        return {"checkout_url": session.checkout_url}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Flask

from flask import Flask, request, jsonify
from dodopayments import DodoPayments
import os

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

@app.route('/api/checkout', methods=['POST'])
def create_checkout():
    data = request.json
    
    session = client.checkout_sessions.create(
        product_cart=[{
            "product_id": data['product_id'],
            "quantity": data.get('quantity', 1)
        }],
        customer={
            "email": data['email'],
            "name": data.get('name')
        },
        return_url=f"{os.environ['APP_URL']}/success"
    )
    
    return jsonify({"checkout_url": session.checkout_url})

---

Go Implementation

package main

import (
    "encoding/json"
    "net/http"
    "os"
    
    "github.com/dodopayments/dodopayments-go"
)

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

type CheckoutRequest struct {
    ProductID string `json:"product_id"`
    Email     string `json:"email"`
    Name      string `json:"name"`
    Quantity  int    `json:"quantity"`
}

func createCheckout(w http.ResponseWriter, r *http.Request) {
    var req CheckoutRequest
    json.NewDecoder(r.Body).Decode(&req)
    
    if req.Quantity == 0 {
        req.Quantity = 1
    }
    
    session, err := client.CheckoutSessions.Create(r.Context(), &dodopayments.CheckoutSessionCreateParams{
        ProductCart: []dodopayments.CartItem{
            {ProductID: req.ProductID, Quantity: req.Quantity},
        },
        Customer: &dodopayments.Customer{
            Email: req.Email,
            Name:  req.Name,
        },
        ReturnURL: os.Getenv("APP_URL") + "/success",
    })
    
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    json.NewEncoder(w).Encode(map[string]string{
        "checkout_url": session.CheckoutURL,
    })
}

---

Handling Success

Query Parameters

The return URL receives these query parameters:

  • status=success - Payment completed
  • session_id - Checkout session ID

Verify Payment Server-Side

Don't rely solely on the redirect. Always verify via webhook:

// Webhook handler confirms payment
app.post('/webhook', async (req, res) => {
  const event = req.body;
  
  if (event.type === 'payment.succeeded') {
    // This is the source of truth
    await fulfillOrder(event.data);
  }
  
  res.json({ received: true });
});

---

Advanced Options

Prefill Customer Info

const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_xxxxx', quantity: 1 }],
  customer: {
    email: 'customer@example.com',
    name: 'John Doe',
    phone: '+1234567890',
    address: {
      line1: '123 Main St',
      city: 'San Francisco',
      state: 'CA',
      postal_code: '94105',
      country: 'US',
    },
  },
  return_url: 'https://yoursite.com/success',
});

Custom Success/Cancel URLs

const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_xxxxx', quantity: 1 }],
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/checkout/success?session_id={CHECKOUT_SESSION_ID}',
});

Subscription with Trial

const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_subscription', quantity: 1 }],
  subscription_data: {
    trial_period_days: 14,
  },
  customer: { email: 'customer@example.com' },
  return_url: 'https://yoursite.com/success',
});

---

Error Handling

try {
  const session = await client.checkoutSessions.create({...});
} catch (error: any) {
  if (error.status === 400) {
    // Invalid parameters
    console.error('Invalid request:', error.message);
  } else if (error.status === 401) {
    // Invalid API key
    console.error('Authentication failed');
  } else if (error.status === 404) {
    // Product not found
    console.error('Product not found');
  } else {
    console.error('Checkout error:', error);
  }
}

---

Resources

Related skills

How it compares

Choose checkout-integration when standardizing on Dodo Payments hosted or overlay flows instead of hand-rolling processor REST calls without the official integration patterns.

FAQ

What checkout methods does Dodo Payments support?

Dodo Payments supports hosted checkout with a full-page redirect via the server-side SDK and overlay checkout that stays on your site through JavaScript. checkout-integration documents when to pick each pattern for one-time and subscription flows.

Does checkout-integration cover subscriptions?

checkout-integration covers both one-time payments and subscription checkout sessions with Dodo Payments. Developers configure the server SDK session and choose hosted redirect or overlay modal delivery for recurring billing.

Is Checkout Integration safe to install?

skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Backend & APIspaymentsecommercepricing

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.