You just made a sale. Your customer paid. Now what?
If you're manually emailing download links, you're leaving money on the table. Automation scales you without scaling your workload. Here's how to build a Stripe webhook that delivers your product the moment payment completes.
The Setup
We'll use:
- Stripe (payment processor)
- Netlify Functions (serverless backend)
- Resend (transactional email)
If you're using a different host (Vercel, AWS Lambda, etc.), the logic is identical — only the deployment changes.
Step 1: Create Your Webhook Endpoint
Your webhook is a simple HTTPS endpoint that Stripe calls every time something happens. Here's the bare minimum:
// netlify/functions/stripe-webhook.js
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
const { Resend } = require("resend");
const resend = new Resend(process.env.RESEND_API_KEY);
exports.handler = async (event) => {
const sig = event.headers["stripe-signature"];
const body = event.body;
let stripeEvent;
try {
stripeEvent = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return {
statusCode: 400,
body: `Webhook Error: ${err.message}`,
};
}
// Handle the charge.succeeded event
if (stripeEvent.type === "charge.succeeded") {
const charge = stripeEvent.data.object;
// Extract customer email
const email = charge.billing_details?.email || charge.receipt_email;
// Send download link email
try {
await resend.emails.send({
from: "no-reply@yourdomain.com",
to: email,
subject: "Your Download is Ready",
html: `<p>Thank you for your purchase!</p><p><a href="https://yourdomain.com/downloads/your-product.zip">Download Your Product</a></p>`,
});
console.log(`Email sent to ${email}`);
} catch (emailErr) {
console.error("Email failed:", emailErr);
return {
statusCode: 500,
body: "Email delivery failed",
};
}
}
return {
statusCode: 200,
body: JSON.stringify({ received: true }),
};
};
Step 2: Deploy It
Push to your Git repo. Netlify auto-deploys. You now have a live endpoint like:
https://yourdomain.netlify.app/.netlify/functions/stripe-webhook
Step 3: Register with Stripe
- Go to Stripe Dashboard → Developers → Webhooks
- Click Add endpoint
- Paste your endpoint URL
- Select
charge.succeededevent - Copy the Signing Secret (starts with
whsec_)
Step 4: Add Your Secrets
Add these to your .env.production:
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
RESEND_API_KEY=re_...
Step 5: Test It
Create a test charge on your Stripe dashboard. Check your email — the download link arrives instantly.
What About Failures?
Stripe retries webhooks automatically if your endpoint returns a 5xx error. Always:
- Log everything — exceptions, email failures, missing data
- Return 200 even if something fails — then handle the error separately
- Set up alerts — if emails fail, you need to know immediately
A simple Slack notification:
if (emailErr) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: "POST",
body: JSON.stringify({
text: `❌ Email delivery failed for ${email}: ${emailErr.message}`,
}),
});
}
Common Issues
"Webhook secret invalid"
- Make sure you're using the right secret from Stripe (different in test vs. live mode)
"Email not sending"
- Check Resend API key is valid
- Verify your domain is authorized in Resend
- Check spam folder (it will arrive there until you verify your domain)
"Customer email is null"
- Stripe doesn't always populate
billing_details.email - Use
receipt_emailas fallback (that's what we do above) - Or store the customer email in Stripe metadata when creating the charge
Next: Scale It
Once this works, you can:
- Personalize emails — include the customer's name, order amount, etc.
- Track delivery — log successful sends to a database
- Deliver different products — look up which product they bought and send the right link
- Offer a discount — attach a coupon code to their next purchase email
The Payoff
Now when someone buys your product at 3 AM, they get their download within seconds. You're asleep. Your system is working.
Need help? Drop a comment. I answer every one.
Build something cool with this? Let me know — I feature the best implementations.
🛒 Check Out My Products
If you're building AI agents or digital products, these might help:
- AI Agent Operating Manual ($29) — The complete playbook for running autonomous AI agents
- Claude Code Workflow Pack ($19) — 5 battle-tested CLAUDE.md configs
- Cold Email Skill Pack ($9) — AI agent skills for cold outreach
- X/Twitter Growth Skill ($9) — Grow your audience with AI
See all products: https://joeybuilt.gumroad.com
Top comments (0)