Next.js · TypeScript

Block disposable email in Next.js

Drop a single Route Handler into your Next.js 15 / App Router project. Calls Piisend server-side so the API key never reaches the browser. Works with any auth library.

The code

// app/api/signup/route.ts
import { NextResponse } from 'next/server';

const PIISEND_URL = 'https://api.piisend.com/api/v1/intelligence/email';

async function isDisposable(email: string) {
  try {
    const r = await fetch(PIISEND_URL, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.PIISEND_API_KEY!}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email }),
      cache: 'no-store',
    });
    if (!r.ok) return false; // fail open
    const data = await r.json();
    return data.signals?.disposable === true;
  } catch {
    return false; // fail open on network / timeout
  }
}

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

  if (await isDisposable(email)) {
    return NextResponse.json(
      { error: 'Please use a permanent email address.' },
      { status: 400 },
    );
  }

  // ...your existing signup logic
  return NextResponse.json({ ok: true });
}

API key

Add `PIISEND_API_KEY=pii_live_...` to `.env.local` and `.env.example`. Never expose the key in client components — keep checks in Route Handlers or Server Actions only.

Fail-open vs fail-closed

The example fails open (allows signup when Piisend is unreachable). Right for most SaaS. For high-fraud verticals, fail closed and show a temporary error instead.

Pair with verification

Disposable detection runs before you send a verification email via Piisend. Combine with double opt-in so anything that slips through still cannot activate without inbox access.

Send verification email with Piisend

After blocking disposable addresses, send OTP and verification mail through the same Piisend account. One API key for intelligence checks and transactional sends.