SaaS Billing & Anti-Fraud

How to Prevent Free Trial Credit Abuse in SaaS using Stripe & MailCheck API

Stop serial free-trial farming, protect your OpenAI / Anthropic API token budgets, and prevent unauthorized multi-account abuse with automated email intelligence.

2026-08-02
6 min read
MailCheck Engineering

Offering a free trial (e.g., 14-day trial or 50 free credits) is one of the most effective conversion strategies for B2B SaaS. However, bad actors and resource hoarders exploit these offers by generating hundreds of throwaway accounts to continuously farm free computational resources (GPU hours, LLM tokens, or email sends).

In this guide, we will implement a production pipeline that pairs Stripe Billing with MailCheck API to block disposable trial abusers before they can provision resources.


1. The Cost of Unchecked Free Trial Abuse

When a single user automates 50 fake trial accounts:

  • Direct Infrastructure Losses: Hundreds of dollars in third-party API calls (e.g. OpenAI GPT-4, ElevenLabs, Claude 3.5 Sonnet).
  • Stripe Authorization Overhead: Increased card validation and customer creation clutter.
  • Skewed Product Analytics: Inflated signup numbers leading to false conversion metrics.

2. Common Evasion Tactics Used by Farmers

  1. Burner Domains: Registering via @tempmail.ninja, @dropmail.me, or @guerrillamail.com.
  2. Subaddressing (Plus Addressing): Appending tags to standard inboxes (e.g. john+trial1@gmail.com, john+trial2@gmail.com).
  3. Catch-All Custom Domains: Buying a $2 .xyz domain and using wildcard inboxes.

MailCheck API automatically flags subaddressing tricks, detects catch-all configurations, and matches against 40M+ active temporary domains.


3. The Pre-Checkout Verification Pipeline

Rather than checking the email after Stripe creates the customer, check the email synchronously before generating the Stripe Checkout Session:

graph LR
    A["User Requests Free Trial"] --> B["MailCheck API Verification"]
    B -->|Disposable / Burner| C["Reject: 'Permanent Email Required'"]
    B -->|Legitimate Domain| D["Create Stripe Customer & Session"]
    D --> E["Redirect User to Stripe Checkout"]

4. Production Node.js / Express / Next.js Implementation

Here is a complete checkout route handler:

import Stripe from 'stripe';
import { NextResponse } from 'next/server';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2023-10-16',
});

export async function POST(req: Request) {
  try {
    const { email, planId } = await req.json();

    if (!email) {
      return NextResponse.json({ error: 'Email is required' }, { status: 400 });
    }

    // 1. Validate Email with MailCheck API (Sub-50ms Edge Check)
    const validationRes = await fetch('https://fadsync-email-validation.p.rapidapi.com/v1/check', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-RapidAPI-Key': process.env.RAPIDAPI_KEY!,
        'X-RapidAPI-Host': 'fadsync-email-validation.p.rapidapi.com'
      },
      body: JSON.stringify({ email })
    });

    const valResult = await validationRes.json();

    // 2. Reject disposable addresses and low-reputation domains
    if (valResult.is_disposable || valResult.recommendation === 'BLOCK') {
      return NextResponse.json({
        error: 'Free trials require a valid business or personal email address. Disposable email services are not allowed.',
        suggestion: valResult.suggestion || null
      }, { status: 422 });
    }

    // 3. Create Stripe Checkout Session with Free Trial Period
    const session = await stripe.checkout.sessions.create({
      payment_method_types: ['card'],
      customer_email: email,
      line_items: [
        {
          price: planId, // e.g. price_pro_monthly
          quantity: 1,
        },
      ],
      mode: 'subscription',
      subscription_data: {
        trial_period_days: 14, // 14-Day Free Trial
      },
      success_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
      cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/pricing`,
    });

    return NextResponse.json({ url: session.url });

  } catch (error: any) {
    console.error('Stripe Trial Creation Error:', error);
    return NextResponse.json({ error: error.message || 'Internal Server Error' }, { status: 500 });
  }
}

5. Multi-Layer Defense Best Practices

  1. Enforce Card Pre-Authorization ($0 Auth): Require entering credit card details for trial activation, preventing pure bot networks.
  2. Combine with IP & Device Fingerprinting: Flag registrations sharing identical device hashes or VPN IP subnets.
  3. Use Domain-Level Lookups: If a single domain provisions more than 5 accounts in an hour, route them to your sales team instead of automated free trials.

Test Live Validation Endpoint

Try the API directly in real-time before implementing the guide instructions.

LIVE VALIDATION ENGINE
mailcheck verify
Enter an email address above to test the cascading validation logic in real-time.