A vendor signs up with a company domain. Your application wants one fast answer: approve or reject?
The network cannot give you that answer. It can give you evidence.
In this tutorial, we will call a domain-intelligence API, normalize its response and return one of three application decisions:
type Decision = "allow" | "review" | "block";
The implementation uses registration, DNS, TLS, HTTPS and browser-header signals. It deliberately does not call a technically healthy site “safe.”
1. Define the boundary
The API can observe:
- RDAP registration age, expiry and status;
- public DNS and nameserver configuration;
- TLS trust, hostname coverage and expiry;
- HTTPS reachability and redirects;
- selected HTTP security headers.
It cannot prove:
- who controls the domain;
- whether the business is legitimate;
- whether the site contains malware or phishing content;
- how the domain will behave tomorrow.
That boundary belongs in code review, product copy and user-facing explanations.
2. Call the endpoint with a deadline
Store the RapidAPI key in the environment. Copy the exact host from the marketplace snippet.
const API_HOST =
"domain-intelligence-website-trust-score.p.rapidapi.com";
async function fetchDomainAudit(domain, { forceRefresh = false } = {}) {
const query = new URLSearchParams({
domain,
timeout_ms: "6000",
force_refresh: String(forceRefresh),
});
const response = await fetch("https://" + API_HOST + "/audit?" + query, {
headers: {
"x-rapidapi-host": API_HOST,
"x-rapidapi-key": process.env.RAPIDAPI_KEY,
},
signal: AbortSignal.timeout(12_000),
});
const body = await response.json();
if (!response.ok) {
const error = new Error(
body?.error?.message ?? "Audit failed with " + response.status,
);
error.status = response.status;
error.requestId = body?.request_id;
throw error;
}
return body;
}
The external timeout is longer than the requested audit timeout so the API can return a structured failure instead of being cut off by the caller first.
3. Normalize only the fields your policy understands
Do not spread the provider response through your whole application. Build an adapter.
function normalizeAudit(raw = {}) {
const findings = Array.isArray(raw.findings) ? raw.findings : [];
return {
domain: raw.domain ?? null,
score: Number.isFinite(raw.score?.value) ? raw.score.value : null,
grade: raw.score?.grade ?? null,
provisional: raw.score?.provisional === true,
maximumPossible: raw.score?.maximum_possible ?? null,
topRecommendation: raw.summary?.top_recommendation ?? null,
severeFindings: findings.filter((finding) =>
["critical", "high"].includes(finding.severity),
),
findings: findings.map(({ code, severity, title, recommendation }) => ({
code,
severity,
title,
recommendation,
})),
checks: raw.checks ?? {},
};
}
Stable finding codes are better policy inputs than human-readable messages, which can change for clarity.
4. Separate evidence from the business decision
function decideVendor(evidence, policy = {}) {
const allowAt = policy.allowAt ?? 75;
const blockBelow = policy.blockBelow ?? 40;
if (evidence.provisional || evidence.score === null) {
return { decision: "review", reason: "incomplete technical evidence" };
}
if (evidence.severeFindings.length > 0) {
return { decision: "block", reason: evidence.severeFindings[0].code };
}
if (evidence.score < blockBelow) {
return { decision: "block", reason: "score below " + blockBelow };
}
if (evidence.score >= allowAt) {
return {
decision: "allow",
reason: "technical posture meets vendor policy",
};
}
return { decision: "review", reason: "mixed technical evidence" };
}
These thresholds are illustrative. A marketplace seller, a payroll vendor and a public-link preview need different policies. Keep the numbers configurable and record the version of the policy used for each decision.
5. Fail into review during outages
A timeout does not make a vendor fraudulent.
export async function assessVendorDomain(domain, policy) {
const checkedAt = new Date().toISOString();
try {
const raw = await fetchDomainAudit(domain);
const evidence = normalizeAudit(raw);
const outcome = decideVendor(evidence, policy);
return { checked: true, checkedAt, ...outcome, evidence };
} catch (error) {
return {
checked: false,
checkedAt,
decision: "review",
reason: "domain evidence temporarily unavailable",
errorCode: error.status === 429 ? "RATE_LIMITED" : "AUDIT_UNAVAILABLE",
requestId: error.requestId,
};
}
}
For transient failures, retry in a worker with exponential backoff. Do not lock a person out because an RDAP server or certificate endpoint was temporarily slow.
6. Test the policy, not a live score
External evidence changes. Unit tests should use fixtures.
import test from "node:test";
import assert from "node:assert/strict";
test("provisional evidence goes to review", () => {
const result = decideVendor({
score: 80,
provisional: true,
severeFindings: [],
});
assert.equal(result.decision, "review");
});
test("a critical finding blocks even with a high score", () => {
const result = decideVendor({
score: 82,
provisional: false,
severeFindings: [{ code: "DOMAIN_EXPIRED", severity: "critical" }],
});
assert.deepEqual(result, {
decision: "block",
reason: "DOMAIN_EXPIRED",
});
});
test("middle scores require review", () => {
const result = decideVendor({
score: 62,
provisional: false,
severeFindings: [],
});
assert.equal(result.decision, "review");
});
Add integration tests with domains you control, but do not assert that a public domain always returns the same score.
7. Add the evidence your workflow still needs
For real vendor onboarding, combine the technical audit with:
- legal-entity and business-registration checks;
- proof of domain control;
- sanctions or compliance screening where appropriate;
- bank-account and payout controls;
- malware/phishing intelligence when security risk requires it;
- human review and an appeal path.
The domain score helps route work. It should not become a black-box denial system.
Try the workflow
The Domain Intelligence & Website Trust Score API returns the five evidence groups, an explainable score, stable finding codes and remediation. The Basic plan includes 50 requests per month.
For the complete score model, bulk example and implementation boundaries, see the StadiaSoft domain reputation checker guide.
Disclosure: I publish the RapidAPI product referenced here. The tutorial intentionally documents what it cannot prove.
Top comments (0)