Overview

This example shows how to set up a webhook handler in your existing app for incoming Stripe events. The handler triggers a task when a checkout.session.completed event is received. This is easily customisable to handle other Stripe events.

Key features

  • Shows how to create a Stripe webhook handler in your app
  • Triggers a task from your backend when a checkout.session.completed event is received

Environment variables

You’ll need to configure the following environment variables for this example to work:

  • STRIPE_WEBHOOK_SECRET The secret key used to verify the Stripe webhook signature.
  • TRIGGER_API_URL Your Trigger.dev API url: https://api.trigger.dev
  • TRIGGER_SECRET_KEY Your Trigger.dev secret key

Setting up the Stripe webhook handler

First you’ll need to create a Stripe webhook handler route that listens for POST requests and verifies the Stripe signature.

Here are examples of how you can set up a handler using different frameworks:

// app/api/stripe-webhook/route.ts
import { NextResponse } from "next/server";
import { tasks } from "@trigger.dev/sdk/v3";
import Stripe from "stripe";
import type { stripeCheckoutCompleted } from "@/trigger/stripe-checkout-completed";
//     👆 **type-only** import

export async function POST(request: Request) {
  const signature = request.headers.get("stripe-signature");
  const payload = await request.text();

  if (!signature || !payload) {
    return NextResponse.json(
      { error: "Invalid Stripe payload/signature" },
      {
        status: 400,
      }
    );
  }

  const event = Stripe.webhooks.constructEvent(
    payload,
    signature,
    process.env.STRIPE_WEBHOOK_SECRET as string
  );

  // Perform the check based on the event type
  switch (event.type) {
    case "checkout.session.completed": {
      // Trigger the task only if the event type is "checkout.session.completed"
      const { id } = await tasks.trigger<typeof stripeCheckoutCompleted>(
        "stripe-checkout-completed",
        event.data.object
      );
      return NextResponse.json({ runId: id });
    }
    default: {
      // Return a response indicating that the event is not handled
      return NextResponse.json(
        { message: "Event not handled" },
        {
          status: 200,
        }
      );
    }
  }
}

Task code

This task is triggered when a checkout.session.completed event is received from Stripe.

trigger/stripe-checkout-completed.ts
import { task } from "@trigger.dev/sdk/v3";
import type stripe from "stripe";

export const stripeCheckoutCompleted = task({
  id: "stripe-checkout-completed",
  run: async (payload: stripe.Checkout.Session) => {
    // Add your custom logic for handling the checkout.session.completed event here
  },
});

Testing your task locally

To test everything is working you can use the Stripe CLI to send test events to your endpoint:

  1. Install the Stripe CLI, and login
  2. Follow the instructions to test your handler. This will include a temporary STRIPE_WEBHOOK_SECRET that you can use for testing.
  3. When triggering the event, use the checkout.session.completed event type. With the Stripe CLI: stripe trigger checkout.session.completed
  4. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of 200.
  5. Then, check the Trigger.dev dashboard and you should see the successful run of the stripe-webhook task.

For more information on setting up and testing Stripe webhooks, refer to the Stripe Webhook Documentation.