Introduction
VerifNow is a validation API for the fields billing and onboarding forms depend on: EU VAT numbers, IBANs, national tax and social identifiers, emails and phone numbers. One API key, one quota, one invoice — instead of three vendors for three fields.
It is built for the developer on the other side of a checkout or a signup form, who has to decide in real time whether to accept what a user just typed.
Why data validation?
Bad data costs money at the point it enters your system:
- An unverified VAT number means reverse-charge invoicing you cannot defend in an audit
- A mistyped IBAN means a transfer that fails days later, with a returned-payment fee
- Disposable addresses inflate your user counts with fake accounts
- Typos frustrate users who genuinely want to sign up — and a typo like
gmial.comresolves to a real domain, so it looks deliverable - Invalid phone numbers lead to failed communications
VerifNow catches these at the point of entry, while the user is still in front of the form.
How it works
VerifNow performs a multi-layer validation pipeline. For email validation, the following checks are performed:
| Check | Description |
|---|---|
| Syntax validation | Ensures the address follows valid email format |
| MX record lookup | Confirms the domain has valid mail exchange records |
| Disposable detection | Flags known throwaway email providers |
| Role account detection | Identifies addresses like info@, admin@, noreply@ |
| Free provider detection | Marks addresses from Gmail, Yahoo, Hotmail, etc. |
| Typo detection | Detects typos and suggests the correct domain |
| Domain age | Reports the age of the domain in days |
| MX provider & quality | Identifies the mail provider and scores its quality |
| Risk scoring | Returns a risk score (0–100) and risk level |
| Deliverability assessment | Evaluates if the email is deliverable |
Base URL
All validation requests are made to:
https://api.verifnow.io/api/v1/validateValidation endpoints
All endpoints accept a POST request with a JSON body containing the value to validate:
{
"value": "user@example.com"
}| Type | Endpoint | Guide |
|---|---|---|
| VAT (EU) | POST /api/v1/validate/vat | Validate VAT |
| IBAN | POST /api/v1/validate/iban | Validate IBAN |
POST /api/v1/validate/email | Validate Email | |
| Phone | POST /api/v1/validate/phone | Validate Phone |
| NIF (Spain) | POST /api/v1/validate/nif | Validate NIF (Spain) |
| NAS (Canada) | POST /api/v1/validate/nas | Validate SIN (NAS) |
| SSN (US) | POST /api/v1/validate/ssn | Validate SSN (US) |
Authentication
VerifNow uses API key authentication. Every request must include your API key in the X-API-KEY header.
X-API-KEY: your_api_key_hereKeep your API key out of your source code and client-side bundles. Use environment variables.
Getting your API key
- Sign up at app.verifnow.io
- Navigate to Settings → API Keys
- Click Create new key
- Copy the key — it will only be shown once
Store it as an environment variable:
# .env.local
VERIFNOW_API_KEY=your_api_key_herePlans & quotas
| Plan | Validations per billing period | Concurrent requests | Max API keys | Overage behavior |
|---|---|---|---|---|
| FREE | 250 | 3 | 1 | Blocked |
| STARTER | 10,000 | 5 | 2 | Billed per unit |
| GROWTH | 50,000 | 10 | 5 | Billed per unit |
| PRO | 150,000 | 25 | 20 | Billed per unit |
- FREE plan: requests are blocked once the limit is reached. FREE runs the same
STANDARDvalidation depth as STARTER — see Validation depth by plan. - Paid plans (STARTER, GROWTH, PRO): requests above the quota are billed per unit at the end of the billing period.
- Concurrent requests: all plans enforce a maximum number of simultaneous requests. Exceeding this returns a
429error. On non-PRO plans, a429can also happen temporarily because of shared server-side concurrency protection, even if you are still within your documented per-plan limit. - Quota reset: quotas are reset at the start of each billing period (e.g., if your subscription started on the 4th, quotas reset every 4th of the month for a monthly subscription).
See Rate Limits for more details.
Response format
All validation responses share a common structure:
{
"valid": true,
"message": "Email address is valid but has risk factors",
"normalizedValue": "user@example.com",
"originalValue": "user@example.com",
"validationLevel": "PREMIUM"
}For email validations, an additional emailDetails field is included:
{
"valid": true,
"message": "Email address is valid but has risk factors",
"normalizedValue": "user@example.com",
"originalValue": "user@example.com",
"validationLevel": "PREMIUM",
"emailDetails": {
"signals": {
"syntax_valid": true,
"mx_valid": true,
"typo_detected": false,
"suggested_domain": null,
"disposable": false,
"role_based": false,
"free_provider": false,
"domain_age_days": 11554,
"mx_provider": "google",
"mx_quality_score": 0.9
},
"risk_score": 30,
"risk_level": "MEDIUM",
"deliverability": "RISKY",
"applied_level": "PREMIUM"
}
}Key fields
| Field | Description |
|---|---|
valid | Whether the value passed validation |
message | Human-readable validation summary |
normalizedValue | The cleaned/normalized version of the input |
originalValue | The original value as submitted |
validationLevel | The validation depth applied (e.g., PREMIUM) |
emailDetails | (Email only) Detailed email-specific signals and scoring |
Risk levels (email)
| Risk Level | Meaning |
|---|---|
LOW | Low risk — safe to use |
MEDIUM | Medium risk — some risk factors detected |
HIGH | High risk — significant risk factors |
Deliverability values (email)
| Deliverability | Meaning |
|---|---|
DELIVERABLE | The email is deliverable with high confidence |
RISKY | The email may be deliverable but has risk factors |
UNDELIVERABLE | The email is invalid, or its risk signals add up to a high risk (for example a likely typo) |
valid is false only for invalid syntax, a domain with no mail records, or a blocked domain. Risk
signals affect deliverability and risk_score, never valid, and the verdict is the same on every
plan.
SDKs & libraries
Node.js and TypeScript
npm install @verifnow/sdkTyped methods for all seven rules, no runtime dependencies, ESM and CommonJS. It throws a typed error when the API is unreachable rather than reporting an unverified value as valid.
- 📦
@verifnow/sdkon npm - 💻 verifnow-node on GitHub
Java and Spring Boot
<dependency>
<groupId>io.verifnow</groupId>
<artifactId>verifnow-spring-boot-starter</artifactId>
<version>2.7.0</version>
</dependency>Auto-configured beans and Jakarta Bean Validation annotations (@VerifNowEmail, @VerifNowIban…).
- 📦
io.verifnow:verifnow-spring-boot-starteron Maven Central - 💻 verifnow-spring on GitHub
- 📖 Example project
If you are on verifnow-spring 2.1.0 or earlier, upgrade. Those versions defaulted to a hostname that does not resolve and, combined with the fail-open default, silently reported every value as valid.
For other languages, use the REST API directly — it’s just a few lines of code. See the Examples section.
Support
- 📧 Email: support@verifnow.io