Codapult
DocsBlogPricingPluginsDemo
Get Codapult
Logo

Build your SaaS with AI. Keep the architecture under control.

Get Codapult

Product

  • Pricing
  • Architecture
  • Modules
  • AI platform
  • Plugins

Developers

  • MCP
  • CLI
  • Documentation
  • Launch your SaaS
  • Build a B2B SaaS

Resources

  • Blog
  • FAQ

Connect

  • Contact
  • GitHub

Compare

  • SaaS template comparison
  • Codapult vs Supastarter
  • Codapult vs Makerkit
  • Codapult vs ShipFast
  • Codapult vs SaaSBold
  • Codapult vs Gravity
  • Codapult vs Nextbase
  • Codapult vs BuilderKit

Featured on

Codapult on LaunchNestCodapult on LaunchNestbetterlaunch.cobetterlaunch.coFeatured on LaunchBuffFeatured on LaunchBuffCodapult on PeerPushCodapult on PeerPushFeatured on LaunchItFeatured on LaunchIt
© 2026 Codapult·All rights reserved·Privacy Policy·Terms of Service
Full source code · One-time purchase · Self-host anywhere
All articles

Getting Started

  • Introduction
  • Quick Start
  • Your First 30 Minutes
  • Project Structure
  • License and Permitted Use
  • Starter Profiles and Recipes
  • Product Recipes

Configuration

  • Environment Variables
  • App Configuration
  • Which Modules Should I Enable?
  • Provider Matrix
  • Capability Coverage

Database

  • Database and Provider Guide
  • Database
  • Migrations

Authentication

  • Authentication
  • OAuth Providers
  • Two-Factor & Passwordless
  • Enterprise SSO (SAML)

Ai

  • AI Runtime Architecture and Evals
  • AI Features
  • Streaming Chat
  • RAG and Semantic Search
  • Quotas and Memory

Teams

  • Teams & Organizations
  • Permissions & RBAC
  • SCIM Provisioning

Security

  • Data Retention Policy
  • Security

Deployment

  • Enterprise E2E Evidence
  • Enterprise Production Readiness
  • Deployment, Backup, and Restore Runbook
  • Deployment
  • Troubleshooting

Payments

  • Payments & Billing
  • Stripe Setup
  • LemonSqueezy Setup
  • Polar Setup
  • Payment Webhooks

Api

  • API Layer
  • tRPC
  • GraphQL

Email

  • Email
  • Email Templates

Infrastructure

  • Infrastructure
  • Self-Hosting
  • File Storage
  • Docker
  • Background Jobs
  • Terraform & Pulumi
  • Kubernetes

Ui

  • UI & Theming

I18n

  • Internationalization

Content Management

  • Content Management

Admin

  • Admin Panel

Monitoring

  • Analytics & Monitoring

Modules

  • Module Architecture
  • Waitlist
  • Audit Log
  • White-Labeling
  • Workflow Automation
  • A/B Testing
  • Welcome Page
  • Referrals
  • GDPR Export and Deletion
  • Promotions
  • Outgoing Webhooks

Plugins

  • Plugin System
  • CRM Plugin
  • Helpdesk Plugin
  • Email Marketing Plugin

Upgrading

  • Upgrading Codapult

Developer Tools

  • AI Agents & IDEs
  • MCP Server
  • Testing
  • Build Your First Feature with Codapult MCP
  • How Guard Blocks an Architectural Regression
Payments

Payment Webhooks

How Codapult handles payment webhooks, extending handlers, and testing locally.

Payment providers notify your app of subscription events via webhooks. Stripe, LemonSqueezy, and Polar webhooks are all handled through the same normalized interface.

Endpoints

ProviderEndpoint
StripePOST /api/webhooks/stripe
LemonSqueezyPOST /api/webhooks/lemonsqueezy
PolarPOST /api/webhooks/polar

Signature Verification

Every incoming webhook is verified against its signing secret before processing. Invalid signatures are rejected with a 400 status. Set the corresponding secret:

  • Stripe: STRIPE_WEBHOOK_SECRET
  • LemonSqueezy: LEMONSQUEEZY_WEBHOOK_SECRET
  • Polar: POLAR_WEBHOOK_SECRET

Handled Events

EventAction
checkout.session.completedActivate subscription, link to user
customer.subscription.createdRecord new subscription
customer.subscription.updatedUpdate plan, seats, or status
customer.subscription.deletedCancel and deactivate subscription

Webhook payloads include metadata (userId, planId) set during checkout creation.

Delivery Logging and Idempotency

All webhook deliveries are logged in the webhook_delivery table with the provider event ID, event type, status, and payload. View delivery history in Admin → Webhooks.

After signature verification, the provider event ID is claimed before subscription or payment side effects run. A repeated delivery of an already pending or successful event is acknowledged without running those side effects again. If processing failed, the same event can be claimed again and retried. The unique (provider, event_id) index makes this safe across concurrent app instances.

Failed deliveries are retried via the webhook-retry background job with exponential backoff.

This prevents duplicate processing of the same provider event. It does not reorder different valid events: deploys should still monitor provider delivery order and reconcile the final subscription state when a provider sends related events out of order.

Extending the Handler

To add custom logic when a payment event occurs, edit the webhook handler in the corresponding route file:

// src/app/api/webhooks/stripe/route.ts
case 'checkout.session.completed':
  await activateSubscription(session);
  // Add your custom logic here:
  // await sendWelcomeEmail(session.customer_email);
  // await provisionResources(session.metadata.planId);
  break;

Testing Locally

Stripe CLI

stripe listen --forward-to http://localhost:3000/api/webhooks/stripe

Trigger test events:

stripe trigger checkout.session.completed
stripe trigger customer.subscription.updated

LemonSqueezy

Use ngrok or a similar tunnel to expose your local server:

ngrok http 3000

Then set the ngrok URL as the webhook endpoint in the LemonSqueezy dashboard.

Polar

Use ngrok or a similar tunnel to expose your local server, then register the tunnel URL as the webhook endpoint in the Polar dashboard. See Polar Setup for the full webhook configuration steps.

Polar SetupAPI Layer