Skip to main content

GitHub Repository

Source code for the FastAPI and Dodo Payments boilerplate.

Overview

The FastAPI boilerplate is a Python backend with Dodo Payments already connected. It has endpoints that create checkout sessions and Customer Portal sessions, a webhook endpoint that verifies signatures, and a pricing page rendered from Jinja2 templates.
This boilerplate uses FastAPI with async route handlers, Pydantic for validation and settings, and the dodopayments Python SDK. The handlers call the synchronous DodoPayments client. To avoid blocking the event loop, switch to AsyncDodoPayments and await its calls.

Features

The boilerplate includes:
  • Quick Setup: Go from clone to a running server in about five minutes.
  • Async Handlers: Route handlers are FastAPI async def functions.
  • Checkout Sessions: A pre-configured checkout endpoint that uses the Python SDK.
  • Webhook Handling: A webhook endpoint that verifies each signature with the SDK’s unwrap method.
  • Customer Portal: An endpoint that creates Customer Portal sessions.
  • Type Safety: Pydantic models validate request bodies, and the code uses type hints.
  • Environment Configuration: pydantic-settings loads and validates the configuration from .env.

Prerequisites

Before you begin, you need:
  • Python 3.9 or later, which the dodopayments SDK requires. Python 3.11 or later is recommended.
  • pip or uv for package management.
  • A Dodo Payments account, to create an API key and a webhook signing secret in the dashboard.

Quick Start

1

Clone the Repository

2

Create Virtual Environment

Set up an isolated Python environment:
Or use uv for faster dependency management:
3

Install Dependencies

Or with uv:
4

Get API Credentials

Sign up at Dodo Payments, then get your credentials from the dashboard:
Create both while the Live Mode switch in the sidebar is off. A test mode key works only with DODO_PAYMENTS_ENVIRONMENT=test_mode, and test mode payments don’t move real money.
5

Configure Environment Variables

Copy the example file to create a .env file in the root directory:
Set the values to your Dodo Payments credentials:
.env
All four variables are required. app/core/config.py loads them with pydantic-settings, and the app fails to start if one is missing or empty. DODO_PAYMENTS_RETURN_URL is where checkout sends the customer after payment.
Don’t commit your .env file to version control. The repository’s .gitignore already excludes it.
6

Add Your Products

Replace the sample products in app/lib/products.py with your own. Set each product_id to the ID of a product under Products in your dashboard. The pricing page displays these products.
7

Run the Development Server

Open http://localhost:8000/docs to see the interactive API documentation.
Swagger UI lists the /api/checkout/, /api/webhook/, and /api/customer-portal/ endpoints, ready to test.
The root URL, http://localhost:8000, serves the pricing page.
app/main.py calls templates.TemplateResponse("index.html", {"request": request, ...}), a signature that Starlette 1.x no longer accepts, so the pricing page returns a 500 error on a fresh install. To fix it, change the call to templates.TemplateResponse(request, "index.html", {"products": products}).

Project Structure

API Endpoints

app/main.py mounts each router under an /api prefix: Each path ends with a slash. FastAPI answers a request to the path without the slash with a 307 redirect, so use the exact path, especially in your webhook URL.

Code Examples

These examples are condensed from the files in app/api/.

Creating a Checkout Session

app/api/checkout.py creates a checkout session and returns its checkout_url. The request body takes a product_id, an optional quantity, and an optional customer object with name and email:

Handling Webhooks

app/api/webhook.py verifies the signature with the SDK’s unwrap method, then branches on the event type:

Customer Portal Integration

app/api/portal.py creates a Customer Portal session for a customer ID and returns the portal link as url:
The pricing page in app/templates/index.html sends a hardcoded customer ID (cus_001) to this endpoint, and a hardcoded name and email to the checkout endpoint. Replace them with the signed-in user’s values.

Webhook Events

The handler in app/api/webhook.py branches on these events: To handle another event, add a branch for its type, such as refund.succeeded for a refund that processed successfully. For every event type, see the Webhook Event Guide. Add your business logic inside the webhook handler to:
  • Update user permissions in your database
  • Send confirmation emails
  • Provision access to digital products
  • Track analytics and metrics

Testing Webhooks Locally

Dodo Payments can’t reach localhost. For local development, use a tool such as ngrok to expose your local server:
Add the ngrok HTTPS URL, followed by /api/webhook/, as an endpoint in your Dodo Payments Dashboard:
Copy the endpoint’s signing secret into DODO_PAYMENTS_WEBHOOK_KEY in .env, then restart the server. The app reads .env only at startup.

Deployment

Docker

The repository doesn’t include a Dockerfile. To run the app in a container, add this Dockerfile to the repository root:
COPY . . copies every file in the build context, including .env. To keep your keys out of the image, add a .dockerignore file that lists .env. Then build the image and run it with your environment file:

Production Considerations

Before deploying to production:
  • Switch DODO_PAYMENTS_ENVIRONMENT to live_mode.
  • Use a live mode API key from the dashboard.
  • Add a webhook endpoint for your production domain, and set DODO_PAYMENTS_WEBHOOK_KEY to its signing secret.
  • Set DODO_PAYMENTS_RETURN_URL to your production URL.
  • Enable HTTPS for all endpoints.

Troubleshooting

Make sure your virtual environment is activated and dependencies are installed:
app/main.py serves static files from app/static, but the repository doesn’t include that directory. Create it with mkdir app/static, then start the server again.
Check for these common causes:
  • The product ID doesn’t exist in your Dodo Payments dashboard.
  • The API key or DODO_PAYMENTS_ENVIRONMENT in .env is wrong. A test mode key works only with test_mode.
The endpoint returns the SDK error in a 400 response. Check the FastAPI logs for detailed error messages.
For local testing, use ngrok to expose your server:
In your Dodo dashboard, add an endpoint with the ngrok URL followed by /api/webhook/, including the trailing slash. Copy that endpoint’s signing secret into DODO_PAYMENTS_WEBHOOK_KEY in your .env file.
  • Make sure DODO_PAYMENTS_WEBHOOK_KEY in .env matches the endpoint’s signing secret.
  • Verify the signature against the raw request body, before you parse it as JSON.
  • Pass all three webhook-id, webhook-timestamp, and webhook-signature headers to client.webhooks.unwrap(). The Standard Webhooks signature covers id.timestamp.body, not the body alone.

Learn More

Python SDK

Complete Python SDK documentation with async support

Webhooks Documentation

Learn about all webhook events and best practices

Checkout Sessions

Deep dive into checkout session configuration

API Reference

Complete Dodo Payments API documentation

Support

For help with the boilerplate:
Last modified on September 26, 2026