Dev.to Security 🔐 Cybersecurity 👁 0 📖 4 min read

Scoring an unknown domain 0 to 100 from public signals, with every penalty documented

A lead or signup arrives from a domain you have never seen. Is it a throwaway, a week-old registration, or a company with a valid certificate and a DMARC policy? Checking that by hand means five lookups. This API runs th

A lead or signup arrives from a domain you have never seen. Is it a throwaway, a week-old registration, or a company with a valid certificate and a DMARC policy? Checking that by hand means five lookups. This API runs them in one call and returns a score plus the reasons.

If you only need the disposable-domain part, the Disposable Email Checker from the same account does just that: Stop Mailinator signups with one GET request. This one adds domain age, SSL and email DNS on top.

The shortest working call

curl --request GET \
  --url 'https://domain-trust-score.p.rapidapi.com/checkTrust?domain=stripe.com' \
  --header 'x-rapidapi-host: domain-trust-score.p.rapidapi.com' \
  --header 'x-rapidapi-key: YOUR_RAPIDAPI_KEY'

JavaScript (Node 18+):

const res = await fetch(
  'https://domain-trust-score.p.rapidapi.com/checkTrust?domain=stripe.com',
  {
    headers: {
      'x-rapidapi-host': 'domain-trust-score.p.rapidapi.com',
      'x-rapidapi-key': process.env.RAPIDAPI_KEY,
    },
  }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data.trustScore, data.riskLevel, data.flags);

Python:

import os, requests

r = requests.get(
    "https://domain-trust-score.p.rapidapi.com/checkTrust",
    params={"domain": "stripe.com"},
    headers={
        "x-rapidapi-host": "domain-trust-score.p.rapidapi.com",
        "x-rapidapi-key": os.environ["RAPIDAPI_KEY"],
    },
    timeout=20,
)
r.raise_for_status()
d = r.json()
print(d["trustScore"], d["riskLevel"], d["flags"])

The call does DNS, registry and TLS lookups, so expect a second or two. The captures below took 2.1 s and 0.9 s. Set a timeout.

The response, field by field

Captured from the live API on 7 Oct 2026 (HTTP 200, 795 bytes):

{
  "domain": "stripe.com",
  "trustScore": 100,
  "riskLevel": "low",
  "flags": [],
  "disposable": false,
  "disposableMatchedDomain": null,
  "freeProvider": false,
  "registeredDomain": "stripe.com",
  "domainAgeDays": 11348,
  "registeredAt": "1995-09-12T04:00:00.000Z",
  "registrar": "SafeNames Ltd.",
  "domainAgeStatus": "ok",
  "domainAgeNote": null,
  "ssl": {
    "https": true,
    "valid": true,
    "error": null,
    "issuer": "DigiCert, Inc.",
    "validTo": "2026-12-10T23:59:59.000Z",
    "daysRemaining": 64
  },
  "email": {
    "hasMx": true,
    "mxHosts": [
      "aspmx.l.google.com",
      "alt1.aspmx.l.google.com",
      "alt2.aspmx.l.google.com",
      "aspmx2.googlemail.com",
      "aspmx3.googlemail.com"
    ],
    "spf": true,
    "dmarc": true,
    "dmarcPolicy": "reject",
    "dkimSelectorsFound": ["google", "mandrill", "s1", "s2"],
    "dkimWildcardDns": false
  },
  "listsUpdatedAt": "2026-10-05T10:09:51.295Z",
  "meta": { "user": "..." }
}
  • trustScore starts at 100 and loses a fixed penalty per flag, never going below 0. riskLevel is low at 75 or more, medium from 45 to 74, high below 45.
  • flags is the part to read. It lists why the score is what it is. For stripe.com it is empty.
  • disposable, disposableMatchedDomain, freeProvider come from public disposable-domain lists.
  • domainAgeDays, registeredAt, registrar come from the public registry (RDAP). domainAgeStatus says ok or why no age is available.
  • ssl is a TLS check on port 443 of the domain you sent, including days until expiry.
  • email is DNS only: MX hosts, SPF, DMARC policy and which of 16 common DKIM selectors exist.
  • meta.user holds the caller's account name, shown as "...".

A bad one, mailinator.com (also 7 Oct 2026, 734 bytes), comes back with trustScore: 30, riskLevel: "high" and flags: ["disposable_domain"]. That is 100 minus the 70-point disposable penalty. The other fields (age 8,497 days, valid SSL, SPF and DMARC present) show the score does not mean the domain is new or broken. It means it is a throwaway mail provider.

The penalties

Flag Points
disposable_domain, domain_does_not_exist 70
domain_does_not_resolve 40
domain_under_30_days_old 30
ssl_invalid 25
domain_under_90_days_old, no_https 15
no_mx_records 10
no_spf, no_dmarc 8
domain_under_1_year_old, ssl_expires_within_14_days 5
dmarc_policy_none 3
no_dkim_on_common_selectors 2

free_email_provider and domain_age_unavailable appear as context and cost nothing. If you disagree with these weights, ignore trustScore and apply your own rules to flags, ssl, email and domainAgeDays.

What it does not do

  • The score is a heuristic from public signals. It is not a guarantee of safety, a certification or a fraud verdict.
  • Domain age needs a public RDAP service. In the project's tests of 150 business domains, .ae, .io, .co, .me, .ru and .pk had none, and .au returned no date or was rate-limited. domainAgeStatus explains this and no penalty applies.
  • DKIM cannot be listed from DNS, so 16 common selectors are probed. Finding none does not prove DKIM is absent, which is why the penalty is only 2.
  • SSL is checked on the domain you send. A mail-only domain with no website gets no_https.
  • It does not look at page content, reputation feeds or blocklists.

Errors

Status When Body
200 Domain read and checked (a domain that does not exist is still 200, with a low score) The result above
400 domain missing {"error":"Pass ?domain=<domain>, for example example.com.","code":400}
400 domain not readable {"error":"Could not read a valid domain from this input.","code":400}
405 Any method other than GET {"error":"Use GET /checkTrust?domain=<domain>.","code":405}
502 Unexpected failure inside the API {"error":"Check failed: ...","code":502}

The error bodies are from the API's own documentation and were not re-run on 7 Oct. Gateway failures (bad key, quota used up) return RapidAPI's own error.

Plan

The free Basic plan on the listing currently shows 300 requests per month. Pro is $29 per month for 10,000.

Listing and playground: https://rapidapi.com/samaanmohammed/api/domain-trust-score

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.