All articles
Developer17 July 20267 min read

How to Verify Email Addresses via API: A Developer's Guide

Verifying email addresses at the point of capture — rather than after bounces accumulate — is the most effective approach to list hygiene. An email verification API lets you check each address as soon as a user enters it, before it ever hits your database.

This guide walks through how to integrate an email verification API into common scenarios, with code examples.

When to use the API vs. bulk verification

| Scenario | Use | |---|---| | Signup form / registration | API (real-time, one address at a time) | | Existing list of addresses | Bulk verification (upload CSV) | | CRM enrichment (automated) | API (per-record enrichment job) | | Pre-send campaign cleanup | Bulk verification | | Form embedded in a mobile app | API |

For real-time scenarios, the API is the right tool. Bulk verification handles historical lists.

Getting an API key

Create an account at stopbouncing.com/register, then navigate to API Keys in your dashboard. Generate a key and store it securely — treat it like a password and never expose it in client-side code.

Basic API call

The verification endpoint accepts a single email address and returns its status.

Endpoint:

GET https://api.stopbouncing.com/v1/verify?email={email}

Required header:

Authorization: Bearer YOUR_API_KEY

Response:

{
  "email": "user@example.com",
  "status": "valid",
  "sub_status": null,
  "domain": "example.com",
  "mx_found": true,
  "smtp_check": true,
  "is_disposable": false,
  "is_role_based": false,
  "is_catch_all": false
}

The status field returns one of three values:

  • valid — the address is deliverable
  • invalid — the address does not exist or cannot receive email
  • unverifiable — the server could not confirm (catch-all, timeout, SPAM block)

JavaScript example

async function verifyEmail(email) {
  const response = await fetch(
    `https://api.stopbouncing.com/v1/verify?email=${encodeURIComponent(email)}`,
    {
      headers: {
        Authorization: `Bearer ${process.env.STOPBOUNCING_API_KEY}`,
      },
    }
  );

  if (!response.ok) {
    throw new Error(`Verification failed: ${response.status}`);
  }

  return response.json();
}

// Usage
const result = await verifyEmail("user@example.com");

if (result.status === "invalid") {
  throw new Error("This email address does not exist. Please check and try again.");
}

if (result.is_disposable) {
  throw new Error("Please use a permanent email address. Temporary addresses are not accepted.");
}

Python example

import os
import requests
from urllib.parse import quote

def verify_email(email: str) -> dict:
    api_key = os.environ["STOPBOUNCING_API_KEY"]
    url = f"https://api.stopbouncing.com/v1/verify?email={quote(email)}"
    response = requests.get(url, headers={"Authorization": f"Bearer {api_key}"}, timeout=10)
    response.raise_for_status()
    return response.json()

# Usage
result = verify_email("user@example.com")

if result["status"] == "invalid":
    raise ValueError("Email address does not exist.")

if result["is_disposable"]:
    raise ValueError("Temporary email addresses are not accepted.")

Integrating into a signup form

The most common use case. Best practice: verify server-side (never client-side), after the user submits the form.

// Next.js API route example
import type { NextRequest } from "next/server";

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

  // Basic format check first (fast, free)
  if (!email?.includes("@")) {
    return Response.json({ error: "Invalid email format" }, { status: 400 });
  }

  // SMTP verification (costs one credit)
  const verification = await fetch(
    `https://api.stopbouncing.com/v1/verify?email=${encodeURIComponent(email)}`,
    {
      headers: { Authorization: `Bearer ${process.env.STOPBOUNCING_API_KEY}` },
    }
  ).then((r) => r.json());

  if (verification.status === "invalid") {
    return Response.json(
      { error: "That email address doesn't appear to exist. Please double-check it." },
      { status: 422 }
    );
  }

  if (verification.is_disposable) {
    return Response.json(
      { error: "Please use a permanent email address — temporary addresses are not accepted." },
      { status: 422 }
    );
  }

  // Proceed with account creation
  // ...
}

Handling unverifiable addresses

Some addresses return unverifiable — typically because the domain uses a catch-all configuration or the mail server timed out. These addresses might be valid or invalid; there's no way to know from outside.

The right approach depends on your context:

  • High-value conversions (enterprise, long sales cycles): accept unverifiable and monitor engagement later
  • Marketing list hygiene: treat unverifiable cautiously — consider sending one email and suppressing on first bounce
  • Free trial signups (fraud-sensitive): reject unverifiable to reduce risk of throwaway addresses
if (verification.status === "unverifiable") {
  // Option 1: Accept but flag for monitoring
  await createUser({ email, verificationStatus: "unconfirmed" });

  // Option 2: Reject for high-risk flows
  return Response.json(
    { error: "We couldn't verify this email address. Please try a different one." },
    { status: 422 }
  );
}

Rate limiting and credits

Each API call consumes one credit. The API is rate-limited per your plan — see your dashboard for current limits. For large-scale enrichment jobs, bulk verification is more efficient than calling the API in a loop.

Error handling

Always handle API errors gracefully — don't block user registration if the verification API is temporarily unavailable.

async function safeVerifyEmail(email: string): Promise<"valid" | "invalid" | "unknown"> {
  try {
    const result = await verifyEmail(email);
    if (result.status === "invalid" || result.is_disposable) return "invalid";
    return "valid";
  } catch {
    // API unavailable — fail open to avoid blocking legitimate signups
    return "unknown";
  }
}

Summary

Integrating email verification at the point of capture is straightforward: one API call per submission, check the status field, handle the three cases (valid, invalid, unverifiable). For full API documentation, see the API reference. Start with 100 free credits — no credit card required.

Ready to clean your email list?

Verify thousands of addresses in minutes. No subscription — pay only for what you use.