Get notified when a Stripe payment fails
Stripe sends its own webhook payload shape, so a small relay verifies the signature and forwards a clean title/message to your phone.
Stripe webhooks POST Stripe’s own event shape — { "type": "invoice.payment_failed", "data": { "object": {...} } } — not something you can point at a Paperplane endpoint directly. The honest recipe is a small relay: receive the Stripe event, verify its signature, forward a Paperplane-shaped payload.
The relay
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
const signature = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.rawBody, signature, process.env.STRIPE_WEBHOOK_SECRET);
} catch {
return res.status(400).send('Invalid signature');
}
if (event.type === 'invoice.payment_failed') {
const invoice = event.data.object;
await fetch('https://<host>/events/<username>/Billing', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'Payment failed',
message: `${invoice.customer_email ?? invoice.customer} — $${(invoice.amount_due / 100).toFixed(2)}`,
priority: 'High',
nature: 'error',
dataJson: JSON.stringify({ invoiceId: invoice.id }),
}),
});
}
res.status(200).send('ok');
}
Verifying stripe-signature matters here specifically: this endpoint is publicly reachable, and skipping verification means anyone who finds the URL can send you a fake “payment failed” page.
Add a resolve button
If you refund or retry the charge from a dashboard you host, attach a callback so the notification can trigger that directly — see the API contract for the shape, and cron/systemd for a simpler starting point if webhook signing feels like overkill for now.