Bêta privéeMailbeam est en bêta privée : l'API publique n'est pas encore ouverte.Rejoindre la liste d'attente

Mailbeam
Stripe + Node.jsIntermédiaire20 minutesMis à jour en janvier 2025

Vérification d'e-mails avant un paiement Stripe

Les adresses fausses et jetables sont un vecteur classique de transactions Stripe frauduleuses. Ce tutoriel ajoute la vérification Mailbeam avant l'appel à stripe.customers.create, ce qui bloque les adresses invalides avant la création de la moindre ressource Stripe.

Prérequis

  • Un compte Stripe avec ses clés d'API
  • Un projet Node.js 18+
  • Une clé d'API Mailbeam (inscription gratuite)

Mise en place

npm install stripe
# .env
MAILBEAM_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxx

L'endpoint de paiement

// server/routes/checkout.ts
import Stripe from "stripe";
import { Router } from "express";
// Pas encore de SDK : voici le wrapper de 12 lignes de /docs/quickstart.
import { verifyEmail } from "./lib/mailbeam";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const router = Router();

router.post("/api/checkout/create-session", async (req, res) => {
  const { email, priceId } = req.body;

  if (!email || !priceId) {
    return res.status(400).json({ error: "email and priceId are required" });
  }

  // Étape 1 : vérifier l'adresse avant de toucher à Stripe
  try {
    const { valid, score, reason } = await verifyEmail(email);

    if (!valid || score < 60) {
      return res.status(422).json({
        error:
          reason === "disposable_domain"
            ? "Merci d'utiliser une adresse e-mail permanente pour finaliser votre achat."
            : "Merci de fournir une adresse e-mail valide.",
        code: reason,
      });
    }
  } catch {
    // Échec permissif — ne bloquez pas un paiement sur une erreur Mailbeam
    console.error("[Mailbeam] vérification échouée, on poursuit le paiement");
  }

  // Étape 2 : créer ou récupérer le Customer Stripe
  let customerId: string;

  const existingCustomers = await stripe.customers.list({
    email,
    limit: 1,
  });

  if (existingCustomers.data.length > 0) {
    customerId = existingCustomers.data[0].id;
  } else {
    const customer = await stripe.customers.create({ email });
    customerId = customer.id;
  }

  // Étape 3 : créer la Checkout Session
  const session = await stripe.checkout.sessions.create({
    customer: customerId,
    payment_method_types: ["card"],
    line_items: [{ price: priceId, quantity: 1 }],
    mode: "subscription",
    success_url: `${req.headers.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${req.headers.origin}/pricing`,
  });

  res.json({ url: session.url });
});

export default router;

Intégration côté front-end

// components/CheckoutButton.tsx
"use client";

import { useState } from "react";

export function CheckoutButton({ email, priceId }: { email: string; priceId: string }) {
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  async function handleCheckout() {
    setLoading(true);
    setError(null);

    const res = await fetch("/api/checkout/create-session", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, priceId }),
    });

    const data = await res.json();

    if (!res.ok) {
      setError(data.error);
      setLoading(false);
      return;
    }

    // Redirection vers Stripe Checkout
    window.location.href = data.url;
  }

  return (
    <div>
      {error && (
        <p className="mb-3 text-sm text-destructive" role="alert">{error}</p>
      )}
      <button
        onClick={handleCheckout}
        disabled={loading}
        className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground disabled:opacity-60"
      >
        {loading ? "Redirection…" : "S'abonner →"}
      </button>
    </div>
  );
}

Bonnes pratiques

  • Vérifiez l'adresse avant stripe.customers.create, pour éviter les clients Stripe orphelins
  • Échouez en mode permissif sur une erreur Mailbeam : ne bloquez pas un revenu à cause d'un souci d'API
  • Cherchez un client Stripe existant par adresse, pour éviter les doublons
  • Servez-vous du champ reason pour donner des messages d'erreur précis

Prochaines étapes