Introduction
The RiskMail API returns a clean disposable / safe verdict for any email domain, plus MX record configuration. Integrate it into your signup flow to block or flag suspicious registrations.
Base URL:
Authentication
Every request needs an API key. Create and manage keys from the API Keys dashboard. Pass the key as the key query parameter — that's the simplest form and works in any HTTP client or browser address bar:
?key=YOUR_API_KEY
Optional · advanced: a bearer token in the Authorization header is also accepted. The header takes precedence when both are present.
Authorization: Bearer YOUR_API_KEY
Rate Limits
Daily quota resets at midnight UTC. Per-second burst limits apply per API key.
| Plan | Daily Queries | Per-second Burst |
|---|---|---|
| Free | 3 | 1 req/s |
| Basic | 5,000 | 10 req/s |
| Premium | 10,000 | 20 req/s |
| Pro | 20,000 | 50 req/s |
Domain Verdict API
Check whether a domain is a known disposable / temporary email provider, a free webmail provider, a business email domain, or a shared-MX tenant.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| input | string | required | A bare domain (mailinator.com) or a full email address ([email protected]). The verdict is computed on the domain part either way. Internationalized domains (e.g. bücher.de, 例え.jp) are normalized to Punycode (xn--…) before classification. |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| key | string | conditional | Your API key. Required unless an Authorization: Bearer header is sent. The header wins when both are present. |
Response Fields
The top level carries the echo of what was checked plus a request_id for support. The verdict itself lives inside result.
| Field | Type | Description |
|---|---|---|
| request_id | string | Per-request id; mirrored on the X-Request-ID header. Quote it in support tickets. |
| input | string | The raw :input path segment you submitted. |
| input_type | enum | domain | email — how we parsed your input. |
| string | The parsed email address, or "" when input_type is domain. | |
| domain | string | The normalized domain that was checked. |
| result | object | The verdict object — see the table below. |
result fields
| Field | Type | Description |
|---|---|---|
| verdict | enum | Primary state. disposable | safe. RiskMail only judges these two — anything ambiguous resolves to safe until manual review reclassifies it. |
| disposable | boolean | true when the domain is a temporary / disposable email provider. |
| temporary | boolean | Alias of disposable; included for client readability. |
| safe | boolean | Inverse of disposable. |
| free_provider | boolean | true for public webmail providers (Gmail, Outlook, Yandex…). Free providers are safe, not disposable. |
| business_email | boolean | true when the domain looks like an organization-owned email domain. |
| shared_mx | boolean | true when MX records point at shared multi-tenant inbound infrastructure (Workspace, M365, AWS SES…). Does NOT make the domain allowlisted. |
| has_mx | boolean | Whether the domain has MX records configured. |
| domain_exists | boolean | Whether the domain resolves through DNS. |
| mx_records | string[] | MX hostnames discovered for the domain (lowercase, trailing dot stripped). |
| mx_ip_address | string[] | Resolved IP addresses for indexed MX hosts when available. Empty array [] when MX IP data has not been indexed. |
| level | enum | Compatibility field. low | critical, mirroring the two-state verdict. |
| recommendation | enum | Compatibility field. allow | block, mirroring the two-state verdict. Use verdict instead. |
| cached | boolean | Whether the verdict was served from cache rather than a fresh DNS lookup. |
Error Codes
| Error Code | HTTP | Description |
|---|---|---|
| invalid_input | 400 | The :input path segment is empty or not a valid domain / email. |
| missing_api_key | 401 | No API key found — neither ?key= nor Authorization: Bearer was sent. |
| api_key_invalid | 401 | API key is malformed, unknown, revoked, or not allowed from this IP. |
| quota_exceeded | 402 | Daily query limit reached. Upgrade your plan to continue. |
| rate_limit_exceeded | 429 | Per-second burst limit exceeded. Retry after a short delay. |
| internal_error | 500 | Server error. Retry with exponential backoff. |
Code Examples
cURL · domain input
curl -s "https://riskmail.io/api/v1/domain/mailinator.com?key=YOUR_API_KEY"
cURL · email input
curl -s "https://riskmail.io/api/v1/domain/[email protected]?key=YOUR_API_KEY"
cURL · Authorization header (optional)
curl -s -H "Authorization: Bearer YOUR_API_KEY" \ "https://riskmail.io/api/v1/domain/mailinator.com"
Node.js
const input = encodeURIComponent('mailinator.com'); // or '[email protected]' const key = encodeURIComponent(process.env.RISKMAIL_API_KEY); const res = await fetch(`https://riskmail.io/api/v1/domain/${input}?key=${key}`); const data = await res.json(); if (data.result?.verdict === 'disposable') { /* reject signup */ }
Python
import httpx, urllib.parse, os input_ = urllib.parse.quote("mailinator.com", safe="") # or "[email protected]" key = urllib.parse.quote(os.environ["RISKMAIL_API_KEY"], safe="") resp = httpx.get(f"https://riskmail.io/api/v1/domain/{input_}?key={key}")
Go
input := url.PathEscape("mailinator.com") // or "[email protected]" key := url.QueryEscape(os.Getenv("RISKMAIL_API_KEY")) resp, err := http.Get("https://riskmail.io/api/v1/domain/" + input + "?key=" + key)