Ask ChatGPT Ask Claude

Domain age and lookalike domain API

Bewary's domain API returns registration and expiry dates and registrar from RDAP, plus age in days. It checks scam list membership, how often its TLD is used for scams and brand imitation by homoglyph, typo, brand plus extra words or brand plus a scam word. The answer includes `verdict`, `reason_codes` and `site.p_scam_site`, Bewary's verdict on a page its worker read in the last 90 days. We measured first-time domain lookups from Europe at a median of 449 ms on October 23, 2026. A call costs 1 credit (30 with deep=true), a free key gets 1,000 credits a month, no card, and it answers in median 449 ms.

Endpoint
GEThttps://api.bewary.app/v1/domain/{host}
Price
1 credit, deep=true 30
Free key
1,000 credits a month, no card
Speed
Median 449 ms, measured
Returns
verdict, p_scam, entities with typed facts, reason codes
MCP tool
lookup_domain

Try it

Free from this page: 10 lookups a day
GET/v1/domain/{host}
Recorded answer, October 31, 2026
Scamp_scam0.9116
Reason codes
High
Fake domain (brand + suspicious TLD)DOMAIN_BRAND_ON_ABUSED_TLD
Medium
Lookalike domainDOMAIN_LOOKALIKE_BRAND_WORD
Entities
domainpaypal-login-secure.topScam

Call it

curl "https://api.bewary.app/v1/domain/paypal-login-secure.top"

Act on the result

Copy-paste code that turns the answer into a decision. It runs with or without BEWARY_API_KEY. TypeScript uses bewary.d.ts.

import os, requests

def domain_risk(host):
    key = os.environ["BEWARY_API_KEY"]          # a free key: bewary.app/account
    headers = {"Authorization": f"Bearer {key}"}
    r = requests.get(f"https://api.bewary.app/v1/domain/{host}", headers=headers, timeout=10)
    r.raise_for_status()
    result = r.json()
    facts = result["entities"][0]["facts"]
    age = facts["age_days"]                # None when the registry has no date
    return {"verdict": result["verdict"], "new_domain": None if age is None else age < 30,
            "imitates": (facts["lookalike"] or {}).get("brand_id")}

print(domain_risk("paypal-login-secure.top"))
# {'verdict': 'scam', 'new_domain': None, 'imitates': 'paypal'}

Response

The fields you will use

verdict
The domain's verdict.
entities[0].facts.age_days
Days since registration. registered_at has the date.
entities[0].facts.lookalike
The brand it imitates and the technique.
entities[0].facts.tld_abuse
How often its TLD is used for scams: low, medium or high.
entities[0].facts.listed
On Bewary's scam list.
{  "schema_version": "1.7.0",  "request_id": "req_01M69WH7A2GYM3D5XTWA82PZ5B",  "checked_at": "2026-10-31T21:06:00Z",  "engine": "bewary-engine/3.0.0",  "models": {    "calibration": "interim-band-v0"  },  "input": {    "kind": "lookup",    "channel": "unknown",    "language": null,    "region": null  },  "verdict": "scam",  "p_scam": 0.9116,  "risk_score": 91,  "confidence": 1,  "classification": null,  "reason_codes": [    "DOMAIN_BRAND_ON_ABUSED_TLD",    "DOMAIN_LOOKALIKE_BRAND_WORD"  ],  "entities": [    {      "id": "e1",      "type": "domain",      "value": "paypal-login-secure.top",      "normalized": "paypal-login-secure.top",      "role": "link_target",      "verdict": "scam",      "p_scam": 0.9116,      "risk_score": 91,      "reason_codes": [        "DOMAIN_BRAND_ON_ABUSED_TLD",        "DOMAIN_LOOKALIKE_BRAND_WORD"      ],      "facts": {        "registrable_domain": "paypal-login-secure.top",        "registered_domain": "paypal-login-secure.top",        "tld": "top",        "tld_abuse": "high",        "registered_at": null,        "expires_at": null,        "age_days": null,        "age_bucket": "unknown",        "registrar": null,        "dns": {          "resolves": false,          "a": null,          "mx": null,          "ns": null        },        "status": "gone",        "cert_first_seen": null,        "lookalike": {          "brand_id": "paypal",          "technique": "brand_word"        },        "platform": "none",        "allowlisted": false,        "listed": false,        "seen_in_checks_7d": null,        "country": null,        "target_countries": null,        "list_count": null,        "site": null,        "platform_status": null,        "registry_status": null,        "hold": null,        "registered": false,        "registration_checked_at": "2026-10-30T19:18:58Z",        "archive": {          "checked_at": "2026-10-30T19:20:08Z",          "captured": false,          "first_capture_at": null,          "last_capture_at": null,          "captured_before_registration": null,          "months_before_registration": null,          "last_capture_before_registration_at": null        },        "first_seen_by_bewary": null,        "first_listed_publicly": null      },      "related": [],      "datasets": [        {          "dataset": "registration",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "dns",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "certificates",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "web_archive",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "threat_feeds",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "threat_aggregates",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "brand_registry",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "platform_pages",          "coverage": "WW",          "in_coverage": true        },        {          "dataset": "community_reports",          "coverage": "WW",          "in_coverage": true        }      ]    }  ],  "signals": [    {      "code": "DOMAIN_BRAND_ON_ABUSED_TLD",      "entity": "e1",      "severity": "high",      "weight": 55,      "source_class": "heuristic",      "p": null,      "dataset": "brand_registry",      "coverage": "WW",      "evidence": {        "brand_id": "paypal",        "tld": "top"      }    },    {      "code": "DOMAIN_LOOKALIKE_BRAND_WORD",      "entity": "e1",      "severity": "medium",      "weight": 35,      "source_class": "heuristic",      "p": null,      "dataset": "brand_registry",      "coverage": "WW",      "evidence": {}    }  ],  "degraded": false,  "degraded_reasons": [],  "cached": false,  "explanation": null}

Real responses, captured from the live API on 2026-10-31. Every response has this shape: see Response format.

Domain facts

Every key is in every response, null when unknown. A key marked Coming stays null until its source ships, so you can code against it now.

KeyTypeMeaning
registrable_domain string or null The owner boundary per the Public Suffix List with its private section: x.pages.dev stays whole. Block by this.
registered_domain string or null The name a registry sold: pages.dev for x.pages.dev. The registration dates and registrar describe this name.
status live | gone | broken | parked | held | unknown or null What the domain is doing now. held: its registry or registrar holds it out of the DNS.
tld string or null The top-level domain.
tld_abuse low | medium | high or null How often this TLD is used for scams.
registered_at timestamp or null Registration date from the public registry (RDAP).
expires_at timestamp or null When the registration expires unless it is renewed (RDAP).
age_days integer or null Days since registration.
age_bucket lt_7d | d7_30 | d30_90 | d90_365 | gt_1y | unknown or null The age as a band, for simple rules.
lookalike object or null The brand it imitates (brand_id) and the technique: homoglyph, typo, brand_word or brand_scam_word. subdomain, tld_swap and userinfo are reserved.
platform none | multi_tenant or null multi_tenant: a site anyone can publish on, so the domain's age vouches for nothing.
allowlisted boolean or null A well-known legitimate domain.
listed boolean or null On Bewary's scam list.
registrar string or null The registrar's name, from RDAP.
registry_status array or null The registry's EPP status codes for registered_domain, such as server_hold or pending_delete.
hold none | registrar | registry | both or null Who holds the name out of the DNS. A hold is how registries and registrars take a domain down.
registered boolean or null false: the registry says no such name is registered, so anyone may register it.
registration_checked_at timestamp or null When the registration record was read. Names on our lists are read again daily.
dns object or null Whether it resolves, its IPs, MX and name servers.
site object or null Our verdict on the site when our worker read its page in the last 90 days, with a calibrated probability (p_scam_site).
platform_status object or null The hosting platform's own answer about the site, such as a takedown page or a phishing warning.
archive object or null The site's history in a public web archive, including captures from before the current registration.
first_seen_by_bewary timestamp or null When our own watch first saw the host, in a new certificate or a registry zone file.
first_listed_publicly timestamp or null When a public list we read first named the host.
country ISO code or null The country its country-code TLD names. null for generic TLDs.
target_countries array or null Countries whose people it is aimed at, from the national lists that name it (PL, TW, DE, US).
list_count integer or null How many lists name it, ours and others'.
cert_first_seenComing timestamp or null When its first TLS certificate was logged.
seen_in_checks_7dComing integer or null How often it appeared in checks this week.

Parameters

NameTypeDescription
hostpath, required string The domain or hostname, e.g. paypal-login-secure.top. Subdomains are fine.
deepquery boolean Also read the page with a model (30 credits, API key required). Default false.

Questions

How do I get a domain's age with an API?

GET /v1/domain/{host}. facts.registered_at, facts.age_days, facts.expires_at and facts.registrar come from the public registration data (RDAP), and age_bucket gives a band such as lt_7d or gt_1y for simple rules. The free domain age checker at bewary.app/check/domain-age makes the same call.

Can it detect lookalike and typosquatting domains?

Yes, for well-known brands. facts.lookalike names the brand and the technique: homoglyph (paypa1.com), typo, brand_word (paypal-login.top) or brand_scam_word. Subdomain, TLD swap and userinfo tricks are reserved values, added to the contract and not reported yet.

Is a new domain a scam?

Not on its own. A domain under 30 days old raises the score, but alone it never makes a scam verdict, because real businesses launch new sites too. It needs a second signal, such as a lookalike brand name.

How fast is it?

Measured median 449 ms for a domain seen for the first time.

Used for

Reason codes it can return

CodeMeaningSeverity
LISTED_BLOCKLISTOn scam blocklistCritical
DOMAIN_ALLOWLISTEDEstablished domain (allowlist)Info
DOMAIN_AGE_GT_1YEstablished domainInfo
DOMAIN_AGE_90D_1YEstablished domain (<1y)Info
DOMAIN_AGE_30_90DRecently-registered domainMedium
DOMAIN_AGE_LT_30DBrand-new domainMedium
DOMAIN_MULTITENANT_PLATFORMHosted on a public platformInfo
DOMAIN_AGE_UNKNOWNDomain age unknownInfo
DOMAIN_LOOKALIKE_BRAND_WORDLookalike domainMedium
DOMAIN_MIXED_SCRIPTFake domain (mixed alphabets)High
DOMAIN_HOMOGLYPH_BRANDFake domain (homoglyph)High
DOMAIN_BRAND_ON_ABUSED_TLDFake domain (brand + suspicious TLD)High
DOMAIN_TYPO_BRANDPossible fake domain (typo)Medium
DOMAIN_BRAND_SCAM_WORDPossible fake domain (brand + scam word)Medium
TLD_HIGH_ABUSERisky domainMedium
DOMAIN_DECEPTIVE_STRUCTUREA brand name placed before an @ so the real host hides after itHigh
DOMAIN_CERT_LT_48HFirst TLS certificate issued in the last 48 hoursMedium
LISTED_CAUTIONOn a broad threat list that also holds spam and malware hostsMedium
PROTECTIVE_DNS_BLOCKEDBlocked by public protective DNS resolversMedium
PLATFORM_TAKEDOWNThe hosting platform took it downHigh
PLATFORM_WARNINGThe platform shows a phishing or malware warning in front of itHigh
DOMAIN_REGISTRY_HOLDThe registry holds the domain out of the DNSHigh
DOMAIN_REGISTRAR_HOLDThe registrar suspended the domainMedium

Reserved codes are in the contract, not emitted yet. All reason codes

Updated · This page as Markdown · Changelog