Was this domain registered last week to look like somebody else
The Domain Risk API returns fraud and brand-protection intelligence as clean JSON.
6 active endpoints. Every call is 1 credit.
- POST/domain-risk/v1/assess
- POST/domain-risk/v1/age
- POST/domain-risk/v1/parked
- POST/domain-risk/v1/typosquat
- POST/domain-risk/v1/reputation
- POST/domain-risk/v1/batch
What Domain Risk endpoints does ReefAPI ship?
6 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Domain Risk API
3 of 6 endpoints, ready to run
A risk score and level with the reasons written out, plus the lifecycle block — age, age band, days to expiry, whether it was registered recently — and the impersonation verdict.
{ "ok": true, "meta": { "api": "domain-risk", "endpoint": "assess", "mode": "live", "latency_ms": 10875.6, "record_count": 1, "cache_hit": false }, "data": { "domain": "secure-paypal-verify-login.com", "registered": false, "available": true, "risk_score": 50, "risk_level": "elevated", "reasons": [ "Unregistered, but the name is a lookalike of 'paypal' (brand_substring) — defensively register or monitor.", "Brand name + a login/secure/verify keyword — classic combosquat shape." ], "lifecycle": null, "signals": { "impersonation": { "brand": "paypal", "kind": "brand_substring", "lookalike": "secure-paypal-verify-login" }, "structural_flags": [ "brand+keyword_combosquat" ] } } }
How the Domain Risk API works
Domain Risk is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 184 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Triaging a domain that turned up in an invoice
Payment-redirection fraud runs on domains that look almost right and were registered a fortnight ago. Both of those are checkable in one call.
{"domain": "secure-paypal-verify-login.com"}Returned an elevated score with two reasons in plain English — the name is a lookalike of a brand, and it pairs that brand with a login/verify keyword.
{"domain": "stripe.com"}The control. A thirty-year-old domain with DNSSEC, a real mail setup and a renewal history scored zero, with the reason saying so.
The reasons are the output, not the score. A number tells an analyst nothing they can put in a ticket; 'brand name plus a verify keyword, registered recently' is something they can act on.
curl -X POST https://api.reefapi.com/domain-risk/v1/assess \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"domain":"google.com","check_parked":false}'{
"ok": true,
"data": { … },
"meta": {
"api": "domain-risk",
"endpoint": "assess",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}The verdict fields, their allowed values, and a measured example of each
domain-risk reads RDAP, DNS over HTTPS, certificate transparency and the domain's own root page. It consults no abuse block-list at all, which is why it can flag a domain that nobody has reported yet. Every scored field has a small closed vocabulary, and the reasons array explains each point in plain English, so you can show a customer why a domain was held.
| Field | Values | Measured example |
|---|---|---|
| risk_level | low, medium, elevated, high, or n/a | google.com low, g00gle.com medium, and an unregistered domain returns n/a |
| risk_score | 0 to 100, or null | google.com 0 with reasons ["No notable risk signals - established/clean profile."], g00gle.com 35 |
| lifecycle.age_band | very_new, new, young, established, mature | github.com at 6,896 days is mature, while an 81-day-old domain is flagged recently_registered |
| lifecycle.expiry_risk | expired, imminent, soon, ok | github.com read soon at 43 days to expiry, google.com read ok at 749 |
| renewal_status | active, renewed/maintained | derived from the RDAP created, updated and expires triple, not from a separate lookup |
| signals.impersonation | null, or brand plus kind plus lookalike | g00gle.com returned brand google, kind homoglyph, lookalike g00gle |
| signals.mail | mx, spf and dmarc booleans | g00gle.com has spf and dmarc true but mx false, a common park-and-protect pattern |
| parked.parked | true, false, or null when the page could not be read | example-login.com returned parked false, for_sale false, confidence medium, http_status 200 |
| reputation_score | 0 to 100 with trust_level high, medium or low | reefapi.com scored 50 and medium at 0.22 years old, with signals written as "- only 81d old" and "+ DMARC policy" |
assess and batch do not produce the same number for the same domain. g00gle.com measured risk_score 35 through assess and 23 through batch, because batch skips the certificate-transparency lookup, which is why has_certificate comes back null there, and skips the parked-page probe entirely. Compare scores only within a single action.
Which signals are facts and which are pattern-matching
Measured on an established brand domain, a fabricated phishing-shaped name and a plain content site. The last row is a cost warning.
Age in days and years, the age band, days to expiry, whether the domain was registered recently and whether it has a renewal history all come from the registration record. These are the strongest inputs to the score because they are not inferences — a domain registered eleven days ago is registered eleven days ago.
The engine names which brand a domain resembles and by what mechanism — a brand substring, a homoglyph, a combosquat pairing with a security keyword. That is a heuristic and the payload treats it as one, returning the matched brand and the kind of match rather than a bare verdict, so an analyst can disagree with it.
The fabricated brand-plus-keyword domain came back unregistered and still scored elevated, with the reason recommending defensive registration or monitoring. For brand protection the interesting names are frequently the ones nobody has taken yet — a scorer that only rates live domains misses the window in which you can do something cheaply.
It fetches the site and reports the markers it found along with a confidence level, rather than inferring parking from DNS alone. A live content page came back not-parked at medium confidence with the marker list empty, which is an honest way of saying nothing was found rather than proving a negative.
Generating variants is instant — a single brand produced two hundred and fifty-nine candidates across sixteen families in well under a second. Checking each one against the registry is a different order of work and can exceed a comfortable request timeout on a large brand. Generate first, then check in batches, or narrow the families you care about.
What people build with Domain Risk
The jobs this data is most often used for.
endpoints
credit per call
Trust-and-safety teams call assess to score domains in signups and transactions before they cause fraud.
Brand-protection tools use typosquat to find lookalike domains impersonating a brand.
Onboarding flows use age and parked to flag freshly-registered or dormant domains in real time.
What Domain Risk data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 184 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/domain-risk/v1/assess \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"domain":"google.com","check_parked":false}'import requests
r = requests.post(
"https://api.reefapi.com/domain-risk/v1/assess",
headers={"x-api-key": REEF_KEY},
json={
"domain": "google.com",
"check_parked": false
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Domain Risk.
Get a free key →Does a high risk score mean the domain is malicious?▾
No, it means the signals look wrong. g00gle.com is registered through MarkMonitor on Google's own nameservers, which is about as legitimate as ownership gets, and it still scores 35 at medium because no TLS certificate has ever been issued for it in CT logs and its name is a homoglyph of google. The reasons array carried exactly those two sentences. Treat the score as a triage ranking and read reasons before you act on it.
What actually makes a domain risky here?▾
Seven structural inputs: RDAP age, expiry and renewal history; the registrar and nameserver provider; DNSSEC; mail hygiene as MX, SPF and DMARC booleans; whether any certificate for the name appears in CT logs; hostname structure, surfaced as structural_flags such as digit_letter_mix; and similarity to a known brand. No reputation feed or abuse block-list is involved, which is the point: a domain registered an hour ago for a phishing run has no reports yet but scores badly on age and certificates.
How does this differ from threat-intel and domain-intel?▾
domain-risk is predictive and structural, threat-intel is reported abuse, and domain-intel is raw records. domain-intel gives you whois, dns, ssl_certs, hosting, subdomains and tech_detect with no verdict attached, threat-intel tells you whether URLHaus, OpenPhish, ThreatFox or Spamhaus have listed the host, and domain-risk is the only one of the three that produces a judgment about a domain nobody has reported. Run domain-risk first on unknown domains, then threat-intel to confirm.
What does typosquat generate, and how long does it take?▾
It builds lookalikes across 16 permutation families and then checks which are actually registered. A measured paypal.com run limited to homoglyph, replacement and omission generated 44 candidates, checked all 44, and found 31 registered and high risk with 1 indeterminate, broken down as replacement 22, omission 5 and homoglyph 4, with rows such as 0aypal.com and aypal.com carrying method dns-fallback. That three-family call took about 43 seconds, and the default all-16 run is considerably heavier. Registration checks are capped at 120, and check_registered false returns candidates only.
How do I check a domain that might not be registered?▾
Use assess or batch, not age. A measured assess on an unregistered .com returned ok true with registered false, available true, risk_level n/a, lifecycle null and a reasons entry saying there is nothing to assess. The same domain through the age action failed on three consecutive attempts across two different unregistered names, so age is only reliable once you already know the domain exists.
risk_score came back as a number but risk_level says n/a. Which one do I trust?▾
risk_level, together with registered. One unregistered domain returned risk_score null and another returned risk_score 8, because its name triggered the structural_flags entry digit_letter_mix even though there was nothing else to score. Both had risk_level n/a and registered false. Branch on registered and risk_level, because a score without a level is a fragment of an assessment rather than a verdict.
When should I call reputation instead of assess?▾
They read the same signals through opposite lenses. assess returns risk_score where high is bad and a reasons array listing only what is wrong. reputation returns reputation_score where high is good, a trust_level of high, medium or low, and a signals array where every entry is prefixed with a plus or a minus so you can render both sides. A measured reefapi.com reputation call returned 50 and medium, penalized for being 81 days old and credited for MX, SPF and DMARC.
What input formats does the domain parameter accept?▾
A bare host, a full URL, a leading www. and an IDN are all accepted and normalized down to the registrable domain before anything is looked up. Something that cannot be parsed as a domain is rejected with MISSING_PARAM and the message that assess requires a valid domain. include_pii defaults to false, which drops the RDAP registrant's personal contact details while keeping the organization, so set it true only if you have a lawful reason to hold that data.
What is the Domain Risk API?▾
Domain Risk API is a ReefAPI endpoint group for domain risk It returns live JSON through POST requests under /domain-risk/v1.
Is the Domain Risk API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Domain Risk calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Domain Risk login or account?▾
No login to Domain Risk is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Domain Risk data?▾
The page example is captured from a live assess call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Domain Risk API use?▾
Domain Risk actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Domain Risk from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call domain-risk actions with the same key, credit pool and JSON envelope used by normal REST requests.
18 Developer Tools APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Domain Risk, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.