6 min read

Stripe Webhook Events Reference

Complete reference for Stripe webhook events processed by iaptic. All webhooks require Stripe API version 2024-11-20.acacia.

Event Types

Subscription Lifecycle

checkout.session.completed

Sent when a checkout session is completed successfully.

{
  type: 'checkout.session.completed',
  data: {
    object: {
      id: string;                // cs_xyz
      subscription: string;      // sub_xyz
      customer: string;         // cus_xyz
      metadata: {
        application_username: string;
        managed_by_iaptic: 'true';
      }
    }
  }
}

customer.subscription.created

Sent when a new subscription is created.

{
  type: 'customer.subscription.created',
  data: {
    object: {
      id: string;               // sub_xyz
      status: 'active' | 'trialing';
      current_period_end: number;
      items: {
        data: [{
          price: { id: string }  // price_xyz
        }]
      },
      metadata: {
        application_username: string;
        managed_by_iaptic: 'true';
      }
    }
  }
}

customer.subscription.updated

Sent when a subscription is updated (plan change, renewal, etc).

{
  type: 'customer.subscription.updated',
  data: {
    object: {
      id: string;
      status: 'active' | 'past_due' | 'canceled';
      cancel_at_period_end: boolean;
      current_period_end: number;
      items: {
        data: [{
          price: { id: string }
        }]
      }
    },
    previous_attributes?: {
      items?: {
        data: [{
          price: { id: string }
        }]
      },
      metadata?: {
        application_username?: string;
      }
    }
  }
}

Payment Events

invoice.paid

Sent when an invoice is paid successfully.

{
  type: 'invoice.paid',
  data: {
    object: {
      id: string;              // in_xyz
      subscription: string;    // sub_xyz
      paid: true;
      amount_paid: number;
      currency: string;
      billing_reason: string;
    }
  }
}

invoice.payment_failed

Sent when an invoice payment fails.

{
  type: 'invoice.payment_failed',
  data: {
    object: {
      id: string;
      subscription: string;
      paid: false;
      attempt_count: number;
      next_payment_attempt?: number;
    }
  }
}

payment_intent.succeeded

Sent when a payment is successfully processed.

{
  type: 'payment_intent.succeeded',
  data: {
    object: {
      id: string;             // pi_xyz
      amount: number;
      currency: string;
      metadata: {
        managed_by_iaptic: 'true';
      }
    }
  }
}

Webhook Processing

Verification

All webhooks must be verified using the signing secret:

const event = stripe.webhooks.constructEvent(
  rawBody,          // Raw request body
  signature,        // Stripe-Signature header
  webhookSecret     // Your webhook secret
);

Required Headers

  • Stripe-Signature: Webhook signature
  • Content-Type: application/json
  • Stripe-Version: 2024-11-20.acacia

Response Codes

  • 200: Event processed successfully
  • 401: Invalid signature
  • 400: Invalid payload
  • 500: Processing error

Event Processing Order

Events should be processed in chronological order:

For new purchases:

  1. customer.subscription.created
  2. payment_intent.succeeded (if the product is a one-time payment)

For subscription updates:

  1. customer.subscription.updated

Metadata Requirements

All managed subscriptions must have:

metadata: {
  managed_by_iaptic: 'true',
  application_username: string  // User identifier
}

Error Handling

Common Issues

  1. Invalid Signature

    try {
      const event = stripe.webhooks.constructEvent(/*...*/);
    } catch (err) {
      if (err.type === 'StripeSignatureVerificationError') {
        return res.status(401).json({ error: 'Invalid signature' });
      }
    }
    
  2. Missing Metadata

    if (!event.data.object.metadata?.managed_by_iaptic) {
      return res.status(400).json({ error: 'Not managed by iaptic' });
    }
    
  3. Wrong API Version

    if (event.api_version !== '2024-11-20.acacia') {
      return res.status(400).json({ error: 'Invalid API version' });
    }
    

Testing Webhooks

Using Stripe CLI:

# Install Stripe CLI
brew install stripe/stripe-cli/stripe

# Listen to webhooks
stripe listen --forward-to localhost:3000/webhook

# Trigger specific events
stripe trigger customer.subscription.created
stripe trigger customer.subscription.updated
stripe trigger invoice.payment_failed