Skip to content

Code examples

JavaScript (Node.js 18+ or browser backend)

const res = await fetch("https://signupsieve.p.rapidapi.com/v1/check", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
    "X-RapidAPI-Host": "signupsieve.p.rapidapi.com",
  },
  body: JSON.stringify({ email, ip: req.ip }),
});
const result = await res.json();

if (result.did_you_mean) {
  return showHint(`Did you mean ${result.did_you_mean}?`);
}
if (result.verdict === "block") {
  return reject("Please use a valid, personal email address.");
}
const user = await createUser({
  email,
  canonical: result.canonical, // unique index on this stops duplicate accounts
  needsVerification: result.verdict === "review",
});

Python

import os, requests

HEADERS = {
    "X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"],
    "X-RapidAPI-Host": "signupsieve.p.rapidapi.com",
}
URL = "https://signupsieve.p.rapidapi.com"

result = requests.post(f"{URL}/v1/check", headers=HEADERS,
                       json={"email": email, "ip": ip}, timeout=10).json()

if result["verdict"] == "block":
    raise ValueError("Please use a valid email address.")

# Later, once the user verifies their email:
requests.post(f"{URL}/v1/feedback", headers=HEADERS,
              json={"email": email, "outcome": "confirmed"}, timeout=10)

PHP

$ch = curl_init("https://signupsieve.p.rapidapi.com/v1/check");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "X-RapidAPI-Key: " . getenv("RAPIDAPI_KEY"),
        "X-RapidAPI-Host: signupsieve.p.rapidapi.com",
    ],
    CURLOPT_POSTFIELDS => json_encode(["email" => $email, "ip" => $_SERVER["REMOTE_ADDR"]]),
]);
$result = json_decode(curl_exec($ch), true);

Keep your RapidAPI key on your server. Never put it in browser or mobile app code.

Next.js (App Router)

A route handler for your signup form. It fails open: if the check times out, the signup goes through.

// app/api/signup/route.ts
export async function POST(req: Request) {
  const { email } = await req.json();
  const ip = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim();

  let result: { verdict?: string; canonical?: string; did_you_mean?: string } = {};
  try {
    const res = await fetch("https://signupsieve.p.rapidapi.com/v1/check", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-RapidAPI-Key": process.env.RAPIDAPI_KEY!,
        "X-RapidAPI-Host": "signupsieve.p.rapidapi.com",
      },
      body: JSON.stringify({ email, ip }),
      signal: AbortSignal.timeout(3000),
    });
    if (res.ok) result = await res.json();
  } catch {
    // Network problem: let the signup through and check it later.
  }

  if (result.did_you_mean) {
    return Response.json({ error: `Did you mean ${result.did_you_mean}?` }, { status: 422 });
  }
  if (result.verdict === "block") {
    return Response.json({ error: "Please use a valid, personal email address." }, { status: 422 });
  }
  // Save result.canonical with a unique index to stop duplicate accounts.
  return Response.json({ ok: true, needsVerification: result.verdict === "review" });
}

Express

A middleware you can put in front of any signup route.

// Behind a load balancer, set app.set("trust proxy", 1) so req.ip is the user's IP.
async function signupSieve(req, res, next) {
  try {
    const r = await fetch("https://signupsieve.p.rapidapi.com/v1/check", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
        "X-RapidAPI-Host": "signupsieve.p.rapidapi.com",
      },
      body: JSON.stringify({ email: req.body.email, ip: req.ip }),
      signal: AbortSignal.timeout(3000),
    });
    if (r.ok) req.signupCheck = await r.json();
  } catch {
    // Fail open on network problems.
  }
  if (req.signupCheck?.verdict === "block") {
    return res.status(422).json({
      error: "Please use a valid, personal email address.",
      did_you_mean: req.signupCheck.did_you_mean,
    });
  }
  next();
}

app.post("/signup", express.json(), signupSieve, createUser);

Laravel

A validation rule. Put your key in config/services.php as signupsieve.key.

use Closure;
use Illuminate\Support\Facades\Http;

$request->validate([
    'email' => ['required', 'email', function (string $attribute, mixed $value, Closure $fail) use ($request) {
        // rescue() returns null on network errors, so the signup goes through.
        $result = rescue(fn () => Http::withHeaders([
            'X-RapidAPI-Key' => config('services.signupsieve.key'),
            'X-RapidAPI-Host' => 'signupsieve.p.rapidapi.com',
        ])->timeout(3)->post('https://signupsieve.p.rapidapi.com/v1/check', [
            'email' => $value,
            'ip' => $request->ip(),
        ])->throw()->json(), null, false);

        if (isset($result['did_you_mean'])) {
            $fail("Did you mean {$result['did_you_mean']}?");
        } elseif (($result['verdict'] ?? null) === 'block') {
            $fail('Please use a valid, personal email address.');
        }
    }],
]);

Example: catching a fake signup

POST /v1/check
{ "email": "qwerty1234@yahoo.com", "ip": "3.5.140.10" }
{
  "email": "qwerty1234@yahoo.com",
  "canonical": "qwerty1234@yahoo.com",
  "account_type": "free",
  "deliverable_domain": true,
  "mail_provider": "yahoo",
  "human_score": 3,
  "verdict": "block",
  "reasons": ["keyboard_pattern", "datacenter_ip", "unnatural_name", "long_digit_run"],
  "ip": { "datacenter": "aws", "tor": false, "signups_from_ip": 1 },
  "check_id": "chk_AbQY_Yyt0JRL1mpGtCtC...",
  "model": "baseline"
}

Example: catching a typo

POST /v1/check
{ "email": "j.o.hn+promo7@gmial.com" }
{
  "canonical": "j.o.hn@gmial.com",
  "did_you_mean": "j.o.hn+promo7@gmail.com",
  "human_score": 9,
  "verdict": "block",
  "reasons": ["domain_typo", "unnatural_name"]
}

Show did_you_mean to the user instead of rejecting them outright.

Block disposable emails by framework

Block disposable emails in Next.js

Call the API from a route handler before you create the user, and reject a block verdict. See the Next.js example above.

Block disposable emails in Express

Add a small middleware in front of your signup route that rejects block and passes everything else through. See the Express example above.

Block disposable emails in Laravel

Use a validation rule on the email field, so a throwaway address fails like any other invalid input. See the Laravel example above.

All three fail open: if the API is slow or unreachable, the signup still goes through.

Ready to try it? 1,000 free checks a month. See the quick start or pricing.

Get free API key