SDKs for Node.js, Python, PHP, Go and Ruby
The official SimpleVerifier clients verify an email address or validate a phone number in a few lines: verifyEmail, verifyPhone and a bulk verifyEmails helper that stays under the 120 calls a minute limit. Errors are typed, and rate limits are retried with backoff. Both wrap the same REST API.
Node.js
TypeScript types included, zero runtime dependencies, ESM and CommonJS. Uses the built-in fetch, so it needs Node 18 or later.
InstallPackages publishing soon
npm install simpleverifierQuickstart
import { SimpleVerifier } from "simpleverifier";
const sv = new SimpleVerifier({ apiKey: process.env.SIMPLEVERIFIER_KEY });
const result = await sv.verifyEmail("[email protected]");
// { email: "[email protected]", status: "valid", reason: "Mailbox exists", mailbox_checked: true }
const phone = await sv.verifyPhone("07911 123456", { country: "GB" });
// { phone_status: "valid", phone_e164: "+447911123456", phone_type: "mobile", ... }
const items = await sv.verifyEmails(emails, { concurrency: 5 });
const valid = items.filter((i) => i.ok && i.result.status === "valid");Python
Sync and asyncio clients with the same methods. Python 3.9 or later, one dependency (httpx), fully typed.
InstallPackages publishing soon
pip install simpleverifierQuickstart
from simpleverifier import SimpleVerifier
sv = SimpleVerifier() # reads SIMPLEVERIFIER_KEY
result = sv.verify_email("[email protected]")
# {"email": "[email protected]", "status": "valid", "reason": "Mailbox exists", "mailbox_checked": True}
phone = sv.verify_phone("07911 123456", country="GB")
items = sv.verify_emails(emails, concurrency=5)
valid = [i.email for i in items if i.ok and i.result["status"] == "valid"]
# asyncio: from simpleverifier import AsyncSimpleVerifierPHP, Go and Ruby
Drafts for three more languages: each a small typed wrapper with retries on 429 that honour Retry-After, clear 402 handling and tests against a local mock server. The Go module is live (go get); PHP and Ruby are coming soon to Packagist and RubyGems, so copy the files or install from GitHub. The drafts are MIT-licensed and each includes tests that run against a local mock server.
PHP
PHP 8.1 or later with ext-curl. Unzip the draft, copy the two files in src/ into your project and require both. Download the draft (zip, MIT) · Source on GitHub
<?php
require "src/Exceptions.php";
require "src/Client.php";
$sv = new SimpleVerifier\Client(); // reads SIMPLEVERIFIER_KEY
$result = $sv->verifyEmail("[email protected]");
echo $result["status"], " ", $result["send_advice"] ?? "";
if ($result["status"] === "invalid") {
// ask the visitor for another address
}Go
Go 1.21 or later, standard library only. go get github.com/Ahmedmkarrar/simpleverifier-go@latest · Source on GitHub
package main
import (
"context"
"fmt"
simpleverifier "github.com/Ahmedmkarrar/simpleverifier-go"
)
func main() {
c, err := simpleverifier.New("") // reads SIMPLEVERIFIER_KEY
if err != nil {
panic(err)
}
res, err := c.Verify(context.Background(), "[email protected]")
if err != nil {
panic(err)
}
fmt.Println(res.Status, res.SendAdvice)
}Ruby
Ruby 2.6 or later, standard library only. Unzip the draft, copy lib/ into your project and require "simpleverifier". Download the draft (zip, MIT) · Source on GitHub
require "simpleverifier"
sv = SimpleVerifier::Client.new # reads SIMPLEVERIFIER_KEY
result = sv.verify_email("[email protected]")
puts "#{result["status"]} #{result["send_advice"]}"
if result["status"] == "invalid"
# ask the visitor for another address
endStep-by-step guides for all five languages: quickstart. Every status code: API errors. Try the API from a REST client: Postman collection, Insomnia export, OpenAPI.
Use it today without a package
Until the packages are on npm and PyPI, paste one of these into your project. They call the same endpoints with a 30-second timeout and retry 429 and 503 responses, and the function names match the SDKs, so switching later is a one-line import change.
Node.js
// simpleverifier.mjs — Node 18+, no dependencies
const BASE = "https://simpleverifier.com/api/v1";
export class SimpleVerifierError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
}
async function call(path, body, retries = 2) {
const res = await fetch(`${BASE}/${path}`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SIMPLEVERIFIER_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
if ((res.status === 429 || res.status === 503) && retries > 0) {
await new Promise((resolve) => setTimeout(resolve, (3 - retries) * 1000));
return call(path, body, retries - 1);
}
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new SimpleVerifierError(data.error ?? res.statusText, res.status);
return data;
}
export const verifyEmail = (email) => call("verify", { email });
export const verifyPhone = (phone, { country, live } = {}) => call("phone", { phone, country, live });Python
# simpleverifier_client.py — Python 3.9+, standard library only
import json, os, time, urllib.error, urllib.request
def _call(path, body, retries=2):
request = urllib.request.Request(
f"https://simpleverifier.com/api/v1/{path}",
data=json.dumps(body).encode(),
headers={
"Authorization": f"Bearer {os.environ['SIMPLEVERIFIER_KEY']}",
"Content-Type": "application/json",
},
)
try:
with urllib.request.urlopen(request, timeout=30) as response:
return json.load(response)
except urllib.error.HTTPError as error:
if error.code in (429, 503) and retries > 0:
time.sleep(3 - retries)
return _call(path, body, retries - 1)
message = json.loads(error.read() or b"{}").get("error", error.reason)
raise RuntimeError(f"SimpleVerifier {error.code}: {message}") from error
def verify_email(email):
return _call("verify", {"email": email})
def verify_phone(phone, country=None, live=None):
body = {"phone": phone}
if country:
body["country"] = country
if live is not None:
body["live"] = live
return _call("phone", body)Errors
Every error the SDKs raise extends SimpleVerifierError, which carries the HTTP status and the JSON error body. Auth and payment errors are never retried.
| Status | Error class | When |
|---|---|---|
| 400 | BadRequestError | The email or phone parameter is missing. |
| 401 | AuthError | The API key is missing, wrong or revoked. |
| 402 | PaymentRequiredError | No API access on the plan, an inactive subscription, or a yearly plan's monthly calls used (retry_after is set for that last case). |
| 429 | RateLimitError | More than 120 calls a minute. Retried automatically with backoff. |
| 503 | ServiceUnavailableError | The service is briefly unavailable. Retried automatically. |
| none | TimeoutError | No response within the timeout (30 seconds by default). |
Open-source disposable email domain list
The 9,913 disposable domains SimpleVerifier blocks are being published as a public CC0 list (domains.txt, domains.json, and curated notes on well-known providers in services.json), with tiny zero-dependency lookup packages. They check the domain only; to confirm the mailbox itself exists, use the API.
Disposable check for Node.js
npm install is-disposable-email-addressDisposable check for Python
pip install is-disposable-email-addressimport { isDisposableEmail } from "is-disposable-email-address";
isDisposableEmail("[email protected]"); // truePackages publishing soon Until then, look up any domain with the free disposable email checker or browse the disposable domain index.
Pricing
The SDKs are free. API access comes with Pro, Business and Agency. Pro includes 10,000 calls a month, then $1.50 per 1,000; Business includes 100,000 and Agency 300,000, then $1.00 per 1,000. Starter has no API access. See pricing.
Common questions
- Is there an official SimpleVerifier SDK?
- Yes: simpleverifier on npm for Node.js and simpleverifier on PyPI for Python. Both cover email verification, phone validation and bulk verification, with typed errors and automatic retries on rate limits. Both are being published now; until then, the copy-paste clients on this page call the same API.
- Do the SDKs respect the 120 calls a minute limit?
- Yes. Each client paces its own requests to 120 a minute by default, and retries a 429 or 503 response with exponential backoff, honouring the Retry-After header when the server sends one. The bulk helper verifies a list with bounded concurrency and reports each address's result or error without stopping the run.
- Can I use the SDK in the browser?
- No. Keep your API key on your server. Anyone who can read a key from your page can use your plan. Call SimpleVerifier from your backend and pass the verdict to your form.
- Is the disposable email domain list open source?
- It is being published as a public CC0 list with small lookup packages for npm and PyPI. Until then you can look up any domain with the free disposable email checker.