> ## Documentation Index
> Fetch the complete documentation index at: https://trigger.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Trigger a task from Stripe webhook events

> This example demonstrates how to handle Stripe webhook events using Trigger.dev.

## 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](https://stripe.com/docs/webhooks) 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:

<CodeGroup>
  ```ts Next.js theme={"theme":"css-variables"}
  // app/api/stripe-webhook/route.ts
  import { NextResponse } from "next/server";
  import { tasks } from "@trigger.dev/sdk";
  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,
          }
        );
      }
    }
  }
  ```

  ```ts Remix theme={"theme":"css-variables"}
  // app/webhooks.stripe.ts
  import { type ActionFunctionArgs, json } from "@remix-run/node";
  import type { stripeCheckoutCompleted } from "src/trigger/stripe-webhook";
  //     👆 **type-only** import
  import { tasks } from "@trigger.dev/sdk";
  import Stripe from "stripe";

  export async function action({ request }: ActionFunctionArgs) {
    // Validate the Stripe webhook payload
    const signature = request.headers.get("stripe-signature");
    const payload = await request.text();

    if (!signature || !payload) {
      return 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 json({ runId: id });
      }
      default: {
        // Return a response indicating that the event is not handled
        return json({ message: "Event not handled" }, { status: 200 });
      }
    }
  }
  ```
</CodeGroup>

## Task code

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

```ts trigger/stripe-checkout-completed.ts theme={"theme":"css-variables"}
import { task } from "@trigger.dev/sdk";
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](https://stripe.com/docs/stripe-cli#install), and login
2. Follow the instructions to [test your handler](https://docs.stripe.com/webhooks#test-webhook). 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](https://cloud.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](https://stripe.com/docs/webhooks).
