Main

Developer Knowledge Base

Email Verification API Guide

Everything in one place: ready-to-run tutorials in your language, your live credits balance, and a complete response field reference.

Method: GET Base URL: https://api.validemail.net/ 1 credit per verification

Quick request

URL
https://api.validemail.net/?email=EMAIL_ADDRESS&token=YOUR_API_KEY

Replace EMAIL_ADDRESS and YOUR_API_KEY with your real values, or sign in to get a personalized URL.

Integration Tutorials

Pick your language and copy the complete, best-practice integration: it verifies an address, automatically retries interim Unknown results, and applies the recommended Score ≥ 80 sending rule.

The fastest way to try the API — run these straight from your terminal.

Verify one address
Shell
curl "https://api.validemail.net/?email=someone@example.com&token=YOUR_API_KEY"
Check your credits balance (free)
Shell
curl "https://api.validemail.net/balance?token=YOUR_API_KEY"
1 · Install the dependency
Shell
pip install requests
2 · Verify an email address
Python
import time

import requests

API_URL = "https://api.validemail.net/"
API_KEY = "YOUR_API_KEY"


def verify_email(email: str, max_retries: int = 3) -> dict:
    """Verify an email address, retrying while the result is still pending."""
    for _ in range(max_retries):
        response = requests.get(API_URL, params={"email": email, "token": API_KEY}, timeout=90)
        response.raise_for_status()
        result = response.json()

        # "Unknown" means the verification is still in progress (e.g. greylisting).
        retry_after = result.get("RetryAfterSeconds")
        if result["State"] == "Unknown" and retry_after:
            time.sleep(retry_after)
            continue

        return result

    return result  # still pending after max_retries — treat as risky


result = verify_email("someone@example.com")

print(f"Valid:  {result['IsValid']}")
print(f"Score:  {result['Score']}")
print(f"State:  {result['State']}")
print(f"Reason: {result['Reason']}")

if result["IsValid"] and result["Score"] >= 80:
    print("Safe to send.")
3 · Check your credits balance (free)
Python
balance = requests.get(
    "https://api.validemail.net/balance",
    params={"token": API_KEY},
    timeout=30,
).json()["balance"]

print(f"Credits remaining: {balance}")

Uses the built-in fetch API — no dependencies (Node.js 18+). Run server-side only so your API key stays private.

1 · Verify an email address
JavaScript (Node.js)
const API_URL = 'https://api.validemail.net/';
const API_KEY = 'YOUR_API_KEY';

const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));

async function verifyEmail(email, maxRetries = 3) {
  let result;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const params = new URLSearchParams({ email, token: API_KEY });
    const response = await fetch(`${API_URL}?${params}`);

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

    result = await response.json();

    // "Unknown" means the verification is still in progress (e.g. greylisting).
    if (result.State === 'Unknown' && result.RetryAfterSeconds) {
      await sleep(result.RetryAfterSeconds);
      continue;
    }

    return result;
  }

  return result; // still pending after maxRetries — treat as risky
}

const result = await verifyEmail('someone@example.com');

console.log(`Valid:  ${result.IsValid}`);
console.log(`Score:  ${result.Score}`);
console.log(`State:  ${result.State}`);
console.log(`Reason: ${result.Reason}`);

if (result.IsValid && result.Score >= 80) {
  console.log('Safe to send.');
}
2 · Check your credits balance (free)
JavaScript (Node.js)
const response = await fetch(`https://api.validemail.net/balance?token=${API_KEY}`);
const { balance } = await response.json();

console.log(`Credits remaining: ${balance}`);

Plain PHP with cURL — works in any framework, from Laravel to WordPress.

1 · Verify an email address
PHP
<?php

const API_URL = 'https://api.validemail.net/';
const API_KEY = 'YOUR_API_KEY';

function verifyEmail(string $email, int $maxRetries = 3): array
{
    $result = [];

    for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
        $url = API_URL . '?' . http_build_query(['email' => $email, 'token' => API_KEY]);

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 90);

        $body = curl_exec($ch);
        if ($body === false) {
            throw new RuntimeException('Request failed: ' . curl_error($ch));
        }

        $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);

        if ($status !== 200) {
            throw new RuntimeException("Request failed with HTTP {$status}: {$body}");
        }

        $result = json_decode($body, true);

        // "Unknown" means the verification is still in progress (e.g. greylisting).
        if ($result['State'] === 'Unknown' && !empty($result['RetryAfterSeconds'])) {
            sleep($result['RetryAfterSeconds']);
            continue;
        }

        return $result;
    }

    return $result; // still pending after $maxRetries — treat as risky
}

$result = verifyEmail('someone@example.com');

echo 'Valid:  ' . ($result['IsValid'] ? 'yes' : 'no') . PHP_EOL;
echo 'Score:  ' . $result['Score'] . PHP_EOL;
echo 'State:  ' . $result['State'] . PHP_EOL;
echo 'Reason: ' . $result['Reason'] . PHP_EOL;

if ($result['IsValid'] && $result['Score'] >= 80) {
    echo 'Safe to send.' . PHP_EOL;
}
2 · Check your credits balance (free)
PHP
$balance = json_decode(
    file_get_contents('https://api.validemail.net/balance?token=' . API_KEY),
    true
)['balance'];

echo "Credits remaining: {$balance}" . PHP_EOL;

Modern .NET with HttpClient and System.Text.Json — no external packages (.NET 6+).

1 · Verify an email address
C#
using System.Net.Http.Json;

const string ApiUrl = "https://api.validemail.net/";
const string ApiKey = "YOUR_API_KEY";

using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(90) };

var result = await VerifyEmailAsync("someone@example.com");

Console.WriteLine($"Valid:  {result.IsValid}");
Console.WriteLine($"Score:  {result.Score}");
Console.WriteLine($"State:  {result.State}");
Console.WriteLine($"Reason: {result.Reason}");

if (result.IsValid && result.Score >= 80)
{
    Console.WriteLine("Safe to send.");
}

async Task<VerificationResult> VerifyEmailAsync(string email, int maxRetries = 3)
{
    VerificationResult? result = null;

    for (var attempt = 0; attempt < maxRetries; attempt++)
    {
        var url = $"{ApiUrl}?email={Uri.EscapeDataString(email)}&token={ApiKey}";
        result = await client.GetFromJsonAsync<VerificationResult>(url)
            ?? throw new InvalidOperationException("Empty response.");

        // "Unknown" means the verification is still in progress (e.g. greylisting).
        if (result.State == "Unknown" && result.RetryAfterSeconds is int retryAfter)
        {
            await Task.Delay(TimeSpan.FromSeconds(retryAfter));
            continue;
        }

        return result;
    }

    return result!; // still pending after maxRetries — treat as risky
}

public sealed record VerificationResult(
    bool IsValid,
    int Score,
    string Email,
    string State,
    string Reason,
    string Domain,
    bool Free,
    bool Role,
    bool Disposable,
    bool AcceptAll,
    bool Tag,
    string MXRecord,
    int? RetryAfterSeconds,
    List<AdditionalInfo> EmailAdditionalInfo);

public sealed record AdditionalInfo(string Key, string Value);
2 · Check your credits balance (free)
C#
var balanceResponse = await client.GetFromJsonAsync<BalanceResponse>(
    $"https://api.validemail.net/balance?token={ApiKey}");

Console.WriteLine($"Credits remaining: {balanceResponse!.Balance}");

public sealed record BalanceResponse(int Balance);

Uses the modern java.net.http.HttpClient (Java 11+) and org.json for parsing.

1 · Add a JSON dependency
Maven
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20240303</version>
</dependency>
2 · Verify an email address
Java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

import org.json.JSONObject;

public class EmailVerifier {

    private static final String API_URL = "https://api.validemail.net/";
    private static final String API_KEY = "YOUR_API_KEY";

    private static final HttpClient CLIENT = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    public static void main(String[] args) throws Exception {
        JSONObject result = verifyEmail("someone@example.com", 3);

        System.out.println("Valid:  " + result.getBoolean("IsValid"));
        System.out.println("Score:  " + result.getInt("Score"));
        System.out.println("State:  " + result.getString("State"));
        System.out.println("Reason: " + result.getString("Reason"));

        if (result.getBoolean("IsValid") && result.getInt("Score") >= 80) {
            System.out.println("Safe to send.");
        }
    }

    static JSONObject verifyEmail(String email, int maxRetries) throws Exception {
        JSONObject result = null;

        for (int attempt = 0; attempt < maxRetries; attempt++) {
            String url = API_URL + "?email=" + URLEncoder.encode(email, StandardCharsets.UTF_8)
                    + "&token=" + API_KEY;

            HttpRequest request = HttpRequest.newBuilder(URI.create(url))
                    .timeout(Duration.ofSeconds(90))
                    .GET()
                    .build();

            HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() != 200) {
                throw new RuntimeException("Request failed with HTTP " + response.statusCode() + ": " + response.body());
            }

            result = new JSONObject(response.body());

            // "Unknown" means the verification is still in progress (e.g. greylisting).
            int retryAfter = result.optInt("RetryAfterSeconds", 0);
            if ("Unknown".equals(result.getString("State")) && retryAfter > 0) {
                Thread.sleep(retryAfter * 1000L);
                continue;
            }

            return result;
        }

        return result; // still pending after maxRetries — treat as risky
    }
}
3 · Check your credits balance (free)
Java
HttpRequest balanceRequest = HttpRequest.newBuilder(
        URI.create("https://api.validemail.net/balance?token=" + API_KEY))
        .GET()
        .build();

HttpResponse<String> balanceResponse = CLIENT.send(balanceRequest, HttpResponse.BodyHandlers.ofString());
int balance = new JSONObject(balanceResponse.body()).getInt("balance");

System.out.println("Credits remaining: " + balance);

Standard library only — net/http and encoding/json (Go 1.18+).

1 · Verify an email address
Go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

const (
	apiURL = "https://api.validemail.net/"
	apiKey = "YOUR_API_KEY"
)

type AdditionalInfo struct {
	Key   string `json:"Key"`
	Value string `json:"Value"`
}

type VerificationResult struct {
	IsValid             bool             `json:"IsValid"`
	Score               int              `json:"Score"`
	Email               string           `json:"Email"`
	State               string           `json:"State"`
	Reason              string           `json:"Reason"`
	Domain              string           `json:"Domain"`
	Free                bool             `json:"Free"`
	Role                bool             `json:"Role"`
	Disposable          bool             `json:"Disposable"`
	AcceptAll           bool             `json:"AcceptAll"`
	Tag                 bool             `json:"Tag"`
	MXRecord            string           `json:"MXRecord"`
	RetryAfterSeconds   *int             `json:"RetryAfterSeconds"`
	EmailAdditionalInfo []AdditionalInfo `json:"EmailAdditionalInfo"`
}

var client = &http.Client{Timeout: 90 * time.Second}

func verifyEmail(email string, maxRetries int) (*VerificationResult, error) {
	var result VerificationResult

	for attempt := 0; attempt < maxRetries; attempt++ {
		query := url.Values{"email": {email}, "token": {apiKey}}
		resp, err := client.Get(apiURL + "?" + query.Encode())
		if err != nil {
			return nil, err
		}

		body, err := io.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return nil, err
		}

		if resp.StatusCode != http.StatusOK {
			return nil, fmt.Errorf("request failed with HTTP %d: %s", resp.StatusCode, body)
		}

		if err := json.Unmarshal(body, &result); err != nil {
			return nil, err
		}

		// "Unknown" means the verification is still in progress (e.g. greylisting).
		if result.State == "Unknown" && result.RetryAfterSeconds != nil {
			time.Sleep(time.Duration(*result.RetryAfterSeconds) * time.Second)
			continue
		}

		return &result, nil
	}

	return &result, nil // still pending after maxRetries — treat as risky
}

func main() {
	result, err := verifyEmail("someone@example.com", 3)
	if err != nil {
		panic(err)
	}

	fmt.Println("Valid: ", result.IsValid)
	fmt.Println("Score: ", result.Score)
	fmt.Println("State: ", result.State)
	fmt.Println("Reason:", result.Reason)

	if result.IsValid && result.Score >= 80 {
		fmt.Println("Safe to send.")
	}
}
2 · Check your credits balance (free)
Go
resp, err := client.Get("https://api.validemail.net/balance?token=" + apiKey)
if err != nil {
	panic(err)
}
defer resp.Body.Close()

var balance struct {
	Balance int `json:"balance"`
}
if err := json.NewDecoder(resp.Body).Decode(&balance); err != nil {
	panic(err)
}

fmt.Println("Credits remaining:", balance.Balance)

Standard library only — net/http and json (Ruby 3.0+).

1 · Verify an email address
Ruby
require 'net/http'
require 'json'

API_URL = 'https://api.validemail.net/'
API_KEY = 'YOUR_API_KEY'

def verify_email(email, max_retries: 3)
  result = nil

  max_retries.times do
    uri = URI(API_URL)
    uri.query = URI.encode_www_form(email: email, token: API_KEY)

    response = Net::HTTP.get_response(uri)
    unless response.is_a?(Net::HTTPSuccess)
      raise "Request failed with HTTP #{response.code}: #{response.body}"
    end

    result = JSON.parse(response.body)

    # "Unknown" means the verification is still in progress (e.g. greylisting).
    retry_after = result['RetryAfterSeconds']
    if result['State'] == 'Unknown' && retry_after
      sleep(retry_after)
      next
    end

    return result
  end

  result # still pending after max_retries — treat as risky
end

result = verify_email('someone@example.com')

puts "Valid:  #{result['IsValid']}"
puts "Score:  #{result['Score']}"
puts "State:  #{result['State']}"
puts "Reason: #{result['Reason']}"

puts 'Safe to send.' if result['IsValid'] && result['Score'] >= 80
2 · Check your credits balance (free)
Ruby
uri = URI('https://api.validemail.net/balance')
uri.query = URI.encode_www_form(token: API_KEY)

balance = JSON.parse(Net::HTTP.get(uri))['balance']
puts "Credits remaining: #{balance}"

Keep your key secret. Run these samples on your backend only — never embed your API key in client-side code, public repositories, or mobile apps.

Credits Balance

Check your remaining verification credits — free to call, never consumes a credit.

URL
https://api.validemail.net/balance?token=YOUR_API_KEY

Replace YOUR_API_KEY with your API key, or sign in to view your live balance URL.

Response

JSON
{
  "balance": 12450
}
Response Guide

Use these fields to make reliable delivery decisions in your product workflow.

JSON response
{
  "IsValid": true,
  "Score": 95,
  "Email": "validemailnet@gmail.com",
  "State": "Deliverable",
  "Reason": "ACCEPTED EMAIL",
  "Domain": "gmail.com",
  "Free": true,
  "Role": false,
  "Disposable": false,
  "AcceptAll": false,
  "Tag": false,
  "MXRecord": "gmail-smtp-in.l.google.com.",
  "RetryAfterSeconds": null,
  "EmailAdditionalInfo": []
}
Field Type Description
IsValidbooleanOverall validation status.
Scoreinteger (0-100)Confidence score. Recommended threshold: 80+.
EmailstringThe exact queried email address.
StatestringDeliverable, Not Deliverable, or Unknown (interim result — retry later).
ReasonstringPrimary SMTP/validation reason (e.g. ACCEPTED EMAIL, REJECTED EMAIL, PENDING, GREYLISTED).
DomainstringExtracted domain from the email.
FreebooleanTrue when provider is free (e.g., Gmail).
RolebooleanTrue for role inboxes (info, support, admin).
DisposablebooleanTrue for temporary/disposable addresses.
AcceptAllbooleanTrue when domain accepts all recipients.
TagbooleanTrue for tagged aliases (user+tag@domain).
MXRecordstringResolved mail exchange server.
RetryAfterSecondsinteger / nullSet only on Unknown interim results: seconds to wait before re-querying for the final verdict.
EmailAdditionalInfoarrayReserved metadata collection.
© ValidEmail.net