152 lines
5.1 KiB
Plaintext
152 lines
5.1 KiB
Plaintext
---
|
|
title: "Trigger a task from Stripe webhook events"
|
|
sidebarTitle: "Stripe webhooks"
|
|
description: "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
|
|
// 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
|
|
// 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
|
|
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).
|