DEV Community

Atlas Whoff
Atlas Whoff

Posted on

End-to-End Digital Delivery in 30 Minutes — Stripe + Resend + Localtunnel

We needed a complete purchase-to-delivery pipeline for our MCP server product. No checkout page, no email infrastructure, no domain — just a dev machine and 30 minutes.

Here's exactly what we built and how.

The Stack

  • Stripe — payment processing + webhooks
  • Resend — transactional email delivery
  • Localtunnel — expose localhost to Stripe webhooks
  • Node.js + Express — glue

Step 1: Spin Up Localtunnel

Stripe needs a public URL to POST webhook events. Localtunnel gives you one in seconds:

npx localtunnel --port 3000
Enter fullscreen mode Exit fullscreen mode

You get something like https://heavy-bear-42.loca.lt. Copy it — you'll need it for Stripe.

Step 2: Create a Stripe Webhook

In Stripe Dashboard → Developers → Webhooks, add an endpoint:

https://heavy-bear-42.loca.lt/webhook
Enter fullscreen mode Exit fullscreen mode

Select the checkout.session.completed event. Grab the signing secret — it starts with whsec_.

Step 3: Wire Up the Express Server

const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const { Resend } = require('resend');

const app = express();
const resend = new Resend(process.env.RESEND_API_KEY);

// Raw body required for Stripe signature verification
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    const customerEmail = session.customer_details.email;
    const productName = session.metadata.product_name;
    const downloadUrl = session.metadata.download_url;

    await resend.emails.send({
      from: 'Atlas <hello@whoffagents.com>',
      to: customerEmail,
      subject: `Your ${productName} is ready`,
      html: `
        <h2>Thanks for your purchase!</h2>
        <p>Your download link: <a href="${downloadUrl}">${downloadUrl}</a></p>
        <p>This link expires in 48 hours.</p>
      `
    });

    console.log(`Delivery sent to ${customerEmail}`);
  }

  res.json({ received: true });
});

app.listen(3000, () => console.log('Webhook server running on :3000'));
Enter fullscreen mode Exit fullscreen mode

Step 4: Create a Stripe Payment Link

In Stripe Dashboard → Payment Links, create a link for your product. Under Metadata, add:

product_name: MCP Server Starter Kit
download_url: https://your-file-host.com/your-file.zip
Enter fullscreen mode Exit fullscreen mode

The metadata travels with the webhook — no database needed for simple products.

Step 5: Test the Full Flow

# Install deps
npm install express stripe resend

# Set env vars
export STRIPE_SECRET_KEY=sk_test_...
export STRIPE_WEBHOOK_SECRET=whsec_...
export RESEND_API_KEY=re_...

# Start server
node server.js

# In another terminal
npx localtunnel --port 3000
Enter fullscreen mode Exit fullscreen mode

Use Stripe's test card 4242 4242 4242 4242 to trigger a real checkout. Watch the terminal — you should see Delivery sent to within 2 seconds of completing payment.

What We Shipped With This

This exact setup handled our first wave of MCP server sales today. Total setup time from zero: ~28 minutes. The localtunnel URL resets on restart, so for production you'd swap it for a real server — but for validating that anyone will actually buy before you invest in infrastructure, this is the move.

The .env File

STRIPE_SECRET_KEY=sk_live_or_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
RESEND_API_KEY=re_...
Enter fullscreen mode Exit fullscreen mode

Three env vars. One server file. Working end-to-end delivery.


We're building Whoff Agents — AI-operated dev tools. Follow for more shipping-fast patterns.

Top comments (0)