Event Handler Example

Example of handling payment events using a simple routing pattern.

type SubscriptionData = any; // Replace with your type
type TransactionData = any;  // Replace with your type

type WebhookEvent<T = any> = {
  meta: { occured_at: string; event_type: string; event_id: string };
  data: T;
};

export class WebhookHandler {
  static async processEvent(event: WebhookEvent) {
    switch (event.meta.event_type) {
      case 'subscription.created':
        await this.handleSubscriptionCreated(event.data as SubscriptionData);
        break;
      case 'subscription.updated':
        await this.handleSubscriptionUpdated(event.data as SubscriptionData);
        break;
      case 'transaction.created':
        await this.handleTransactionCreated(event.data as TransactionData);
        break;
      case 'transaction.updated':
        await this.handleTransactionUpdated(event.data as TransactionData);
        break;
      default:
        console.log(`Unhandled event type: ${event.meta.event_type}`);
    }
  }

  static async handleSubscriptionCreated(data: SubscriptionData) {
    // Example: create or enable access for the user
    await db.subscriptions.create({
      userId: data.customer?.id,
      planName: data.items?.[0]?.planName,
      status: data.status,
      currentPeriodEnd: data.nextBilledAt
    });
  }

  static async handleSubscriptionUpdated(data: SubscriptionData) {
    await db.subscriptions.update({
      id: data.id,
      status: data.status,
      pausedAt: data.pausedAt,
      canceledAt: data.canceledAt
    });
  }

  static async handleTransactionCreated(data: TransactionData) {
    await db.transactions.create({
      id: data.id,
      amount: data.totalAmountPaid,
      currency: data.paidCurrency,
      status: data.status
    });
  }

  static async handleTransactionUpdated(data: TransactionData) {
    await db.transactions.update({
      id: data.id,
      status: data.status,
      revisedAt: data.revisedAt
    });
  }
}

Notes:

  • Use idempotency (by meta.event_id or a delivery header) to avoid double-processing.

  • Validate payloads and handle unknown fields defensively.

Last updated