Skip to main content
This page documents all webhook events handled by the Dodo Supabase Subscription Starter kit.

Event Structure

All webhook events follow this structure:
{
  type: string,        // Event type identifier
  data: {
    // Event-specific payload
    customer: {
      customer_id: string,
      email: string,
      name: string
    },
    // Additional fields...
  }
}

Payment Events

Payment events track the lifecycle of payment transactions.

payment.succeeded

Fired when a payment is successfully completed. Handler: managePayment() at supabase/functions/dodo-webhook/index.ts:120
data.payment_id
string
required
Unique identifier for the payment
data.status
string
required
Payment status (e.g., “succeeded”)
data.total_amount
number
required
Total payment amount
data.currency
string
required
Three-letter currency code (e.g., “USD”)
data.payment_method
string
Payment method identifier
data.payment_method_type
string
Type of payment method (e.g., “card”)
data.subscription_id
string
required
Associated subscription identifier
data.customer
object
required
Customer information object
data.customer.customer_id
string
required
Dodo customer identifier
data.customer.email
string
required
Customer email address
data.customer.name
string
Customer name
data.created_at
string
required
ISO 8601 timestamp of payment creation
data.updated_at
string
ISO 8601 timestamp of last update
data.brand_id
string
required
Brand identifier
data.business_id
string
required
Business identifier
data.metadata
object
Custom metadata object
data.billing
object
Billing information object
data.card_last_four
string
Last four digits of card number
data.card_network
string
Card network (e.g., “Visa”, “Mastercard”)
data.card_type
string
Card type (e.g., “credit”, “debit”)
data.card_issuing_country
string
ISO country code of card issuer
data.tax
number
Tax amount
data.settlement_amount
number
Settlement amount in settlement currency
data.settlement_currency
string
Currency code for settlement
data.settlement_tax
number
Tax amount in settlement currency
data.discount_id
string
Applied discount identifier
Payment link URL
data.product_cart
object
Product cart details
data.refunds
object
Refund information
data.disputes
object
Dispute information

payment.failed

Fired when a payment fails. Handler: managePayment() at supabase/functions/dodo-webhook/index.ts:120 Includes all fields from payment.succeeded plus:
data.error_code
string
Error code describing the failure
data.error_message
string
Human-readable error message

payment.processing

Fired when a payment is being processed. Handler: managePayment() at supabase/functions/dodo-webhook/index.ts:120 Uses the same payload structure as payment.succeeded.

payment.cancelled

Fired when a payment is cancelled. Handler: managePayment() at supabase/functions/dodo-webhook/index.ts:120 Uses the same payload structure as payment.succeeded.

Subscription Events

Subscription events track the lifecycle of recurring subscriptions.

subscription.active

Fired when a subscription becomes active. Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Side Effect: Updates user’s current_subscription_id via updateUserTier() at line 201
data.subscription_id
string
required
Unique identifier for the subscription
data.status
string
required
Subscription status (e.g., “active”)
data.product_id
string
required
Product identifier
data.quantity
number
required
Subscription quantity
data.recurring_pre_tax_amount
number
required
Recurring amount before tax
data.tax_inclusive
boolean
required
Whether pricing includes tax
data.currency
string
required
Three-letter currency code
data.customer
object
required
Customer information
data.customer.customer_id
string
required
Dodo customer identifier
data.customer.email
string
required
Customer email address
data.customer.name
string
Customer name
data.created_at
string
required
ISO 8601 timestamp of subscription creation
data.next_billing_date
string
required
ISO 8601 timestamp of next billing
data.previous_billing_date
string
required
ISO 8601 timestamp of previous billing
data.payment_frequency_interval
string
Billing frequency interval (e.g., “month”, “year”)
data.payment_frequency_count
number
Number of intervals between payments
data.subscription_period_interval
string
Subscription period interval
data.subscription_period_count
number
Number of subscription periods
data.trial_period_days
number
Length of trial period in days
data.billing
object
required
Billing information
data.metadata
object
Custom metadata
data.discount_id
string
Applied discount identifier
data.addons
object
Subscription addons
data.on_demand
boolean
Whether subscription is on-demand
data.cancel_at_next_billing_date
boolean
Whether subscription will cancel at next billing
data.cancelled_at
string
ISO 8601 timestamp of cancellation

subscription.plan_changed

Fired when a subscription plan is changed (upgrade/downgrade). Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Side Effect: Updates user’s current_subscription_id via updateUserTier() at line 201 Uses the same payload structure as subscription.active.

subscription.renewed

Fired when a subscription is renewed. Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Uses the same payload structure as subscription.active.

subscription.on_hold

Fired when a subscription is placed on hold. Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Uses the same payload structure as subscription.active.

subscription.cancelled

Fired when a subscription is cancelled. Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Side Effect: Sets user’s current_subscription_id to null via downgradeToHobbyPlan() at line 214 Uses the same payload structure as subscription.active.

subscription.expired

Fired when a subscription expires. Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Side Effect: Sets user’s current_subscription_id to null via downgradeToHobbyPlan() at line 214 Uses the same payload structure as subscription.active.

subscription.failed

Fired when a subscription fails (e.g., payment failure). Handler: manageSubscription() at supabase/functions/dodo-webhook/index.ts:164 Side Effect: Sets user’s current_subscription_id to null via downgradeToHobbyPlan() at line 214 Uses the same payload structure as subscription.active.

Event Flow Examples

New Subscription Flow

  1. payment.processing - Initial payment begins
  2. payment.succeeded - Payment completes
  3. subscription.active - Subscription activated, user tier updated

Subscription Cancellation Flow

  1. subscription.cancelled - Subscription cancelled, user downgraded
  2. Future payment events stop

Failed Payment Flow

  1. payment.processing - Payment attempt begins
  2. payment.failed - Payment fails with error details
  3. subscription.failed - Subscription marked as failed, user downgraded

Testing Webhooks

During development, you can test webhook events using:
  1. Dodo Dashboard: Send test events from your Dodo Payments dashboard
  2. Local Testing: Use ngrok or similar to expose your local Supabase function
  3. Replay Events: Re-send previous webhook events from the Dodo dashboard
All webhook events are idempotent - replaying the same event will not create duplicates due to upsert operations.

Build docs developers (and LLMs) love