Note:
HeliumTS is under pre-beta and active development. Expect bugs and breaking changes. If you find any issues, please report them in our GitHub
A stable release is planned for early December 2025.
Stripe Webhooks
This guide shows how to handle Stripe webhooks with HeliumTS.
Setup
First, install the Stripe SDK:
%npm install stripe
Add your Stripe keys to your environment variables:
%STRIPE_SECRET_KEY=sk_test_...%STRIPE_WEBHOOK_SECRET=whsec_...
Webhook Handler
Handle Stripe webhooks to process events like successful payments:
1import { defineHTTPRequest } from "heliumts/server";2import Stripe from "stripe";34const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {5 apiVersion: "2024-11-20.acacia",6});78export const stripeWebhook = defineHTTPRequest("POST", "/webhooks/stripe", async (req, ctx) => {9 const body = await req.text();10 const signature = req.headers["stripe-signature"] as string;1112 if (!signature) {13 return new Response(JSON.stringify({ error: "No signature" }), {14 status: 400,15 headers: { "Content-Type": "application/json" },16 });17 }1819 try {20 const event = stripe.webhooks.constructEvent(21 body,22 signature,23 process.env.STRIPE_WEBHOOK_SECRET!24 );2526 // Handle different event types27 switch (event.type) {28 case "payment_intent.succeeded": {29 const paymentIntent = event.data.object as Stripe.PaymentIntent;30 console.log("Payment succeeded:", paymentIntent.id);31 // Update your database, send confirmation email, etc.32 break;33 }3435 case "checkout.session.completed": {36 const session = event.data.object as Stripe.Checkout.Session;37 console.log("Checkout completed:", session.id);38 // Fulfill the order39 break;40 }4142 case "customer.subscription.created": {43 const subscription = event.data.object as Stripe.Subscription;44 console.log("Subscription created:", subscription.id);45 // Update user's subscription status46 break;47 }4849 case "customer.subscription.deleted": {50 const subscription = event.data.object as Stripe.Subscription;51 console.log("Subscription cancelled:", subscription.id);52 // Revoke access53 break;54 }5556 case "invoice.payment_failed": {57 const invoice = event.data.object as Stripe.Invoice;58 console.log("Payment failed:", invoice.id);59 // Notify customer60 break;61 }6263 default:64 console.log(`Unhandled event type: ${event.type}`);65 }6667 return new Response(JSON.stringify({ received: true }), {68 status: 200,69 headers: { "Content-Type": "application/json" },70 });71 } catch (error) {72 console.error("Webhook error:", error);7374 return new Response(75 JSON.stringify({ error: "Webhook signature verification failed" }),76 {77 status: 400,78 headers: { "Content-Type": "application/json" },79 }80 );81 }82});
Testing Webhooks Locally
Use Stripe CLI to forward webhooks to your local server:
%# Install Stripe CLI%brew install stripe/stripe-cli/stripe%%# Login to Stripe%stripe login%%# Forward webhooks to your local server%stripe listen --forward-to localhost:3000/webhooks/stripe
The CLI will output your webhook signing secret. Add it to your .env file.
Best Practices
- Always verify webhook signatures to prevent fraud
- Use environment variables for API keys and secrets
- Handle webhook events idempotently (same event may be sent multiple times)
- Return a 200 response quickly to acknowledge receipt
- Process webhook events asynchronously if they take time
- Log all webhook events for debugging
- Test with Stripe test mode before going live
- Implement proper error handling and monitoring