Introduction
A WHOIS API call looks simple: authenticate, pass a domain, parse JSON. In production, one design choice dominates cost and correctness — whether you accept a cached response or force a live registry lookup.
WhoisJSON caches successful WHOIS responses for about three hours. Most portfolio scans, onboarding checks and scheduled monitors should use that cache. Force-refresh exists for the minority of requests where stale registry data is wrong: post-transfer verification, incident response, expiry-cliff decisions and change confirmation.
This article explains the cache contract, the_forceRefresh=1 query parameter, credit cost, decision rules, and copy-paste patterns in Python and Node.js. It complements rate limits and 429 retries — cache controls freshness; rate limits control throughput.
Why WHOIS APIs Cache Responses
WHOIS and RDAP lookups depend on upstream registries and thin clients. Caching is not a shortcut around accuracy — it is how production APIs stay fast, fair and resilient.
- Latency. Cached JSON returns in milliseconds. Live WHOIS can take hundreds of milliseconds to several seconds depending on the TLD.
- Upstream protection. Registries and WHOIS servers are not designed for uncontrolled polling. Caching absorbs repeated lookups for the same domain.
- Cost predictability. Default requests consume one credit. Live force-refresh costs more because it hits the origin path.
- Stable integrations. Bulk jobs and dashboards stay responsive when popular domains are served from cache instead of waiting on every registry round-trip.
How the WhoisJSON WHOIS Cache Works
On a normalGET /api/v1/whois?domain=example.com request (no force-refresh flag):
- The API checks Redis for a recent WHOIS payload for that domain.
- If a valid cache entry exists, it returns the cached JSON immediately.
- If not, it queries the live WHOIS/RDAP path, normalizes the response, stores it with a TTL near three hours, and returns the result.
Cached responses include the same structured fields as live responses — registrar, dates, EPP status, nameservers — so your parsers do not change. Treat cache as an acceleration layer, not a different schema.
| Behavior | Default request | With _forceRefresh=1 |
|---|---|---|
| Data source | Cache if fresh, else live | Prefer live registry path |
| Typical latency | Faster (cache hit) | Higher (upstream round-trip) |
| Credit cost | 1 credit | 2 credits |
| Plan availability | All plans | Pro and above |
| Best for | Scans, monitors, dashboards | Incidents, transfers, confirmations |
What _forceRefresh=1 Does
Append_forceRefresh=1 to the query string to ask for live data instead of a cached payload:
GET /api/v1/whois?domain=example.com&_forceRefresh=1
Authorization: Token=YOUR_API_KEYImportant product rules (also documented on documentation and FAQs):
- Force-refresh costs 2 credits instead of 1.
- It is available on Pro plans and above.
_forceRefresh=1 doubles credit burn and adds unnecessary load for data that rarely changes within three hours.When the Default Cache Is Enough
Use the default cached path unless you have a concrete reason to pay for live data.
- Daily or hourly portfolio expiry scans
- SaaS onboarding that checks registration age or registrar once per signup
- CI/CD domain health gates on every deploy (expiry and lock presence)
- Security dashboards that baseline registrar, NS and EPP status
- Bulk WHOIS enrichment where “within three hours” is acceptable truth
- Deduplicated jobs that look up the same domain many times in one run
For high-volume enrichment patterns, see the Bulk WHOIS API product page and the bulk WHOIS guide.
When You Should Force Refresh
Force-refresh when a wrong answer from a three-hour-old snapshot would cause a bad operational decision.
- Post-transfer verification. Confirm the gaining registrar and re-enabled
clientTransferProhibitedafter an authorized move (see the transfer security checklist). - Incident / hijack triage. After an alert on lock removal or NS change, fetch live WHOIS before escalating.
- DNS or SSL change confirmation. After a cutover, force-refresh
nslookupor SSL to confirm propagation — not for every routine poll. - Expiry-cliff decisions. Hours before auto-renew or drop risk, prefer live
expiresover a cached date. - Customer support “is it done yet?” When a user just changed registrar settings and needs confirmation now.
_forceRefresh=1 for domains that failed a policy check or were flagged by monitoring.Decision Matrix: Cache vs Force Refresh
| Scenario | Use cache? | Force refresh? |
|---|---|---|
| Nightly expiry report (5,000 domains) | Yes | No |
| Same domain looked up 40 times in one job | Yes (dedupe + cache) | No |
| Alert: transfer lock missing on apex | First look: cache OK | Confirm + escalate: yes |
| Transfer completed 10 minutes ago | No | Yes |
| DNS cutover just pushed | Optional first check | Yes on verification pass |
| “Refresh all domains every 5 minutes” | No — redesign the job | Never as a default |
Common Mistakes
- Appending
_forceRefresh=1to every client helper “just in case”. - Confusing cache freshness withHTTP 429 rate limits — fixing one does not fix the other.
- Treating a cached response as “wrong” when the registry simply has not updated yet.
- Force-refreshing Free/Basic plans expecting live data without checking plan eligibility.
- Ignoring the 2× credit cost in budget forecasts for monitoring fleets.
- Forgetting that DNS and SSL also support force-refresh — and burning credits on both when only one signal changed.
Python: Cached Lookup vs Force Refresh
import os
import requests
API_KEY = os.environ["WHOISJSON_API_KEY"]
BASE = "https://whoisjson.com/api/v1/whois"
def whois_lookup(domain: str, force_refresh: bool = False) -> dict:
params = {"domain": domain}
if force_refresh:
params["_forceRefresh"] = 1
response = requests.get(
BASE,
params=params,
headers={"Authorization": f"Token={API_KEY}"},
timeout=30,
)
response.raise_for_status()
return response.json()
# Default: 1 credit, may be served from the 3-hour cache
cached = whois_lookup("example.com")
# Live path: 2 credits, Pro+ — use only when freshness matters
live = whois_lookup("example.com", force_refresh=True)
print(cached.get("registrar", {}).get("name"))
print(live.get("expires"))
Node.js: Selective Force Refresh After a Flag
const API_KEY = process.env.WHOISJSON_API_KEY;
const BASE = 'https://whoisjson.com/api/v1/whois';
async function whoisLookup(domain, { forceRefresh = false } = {}) {
const url = new URL(BASE);
url.searchParams.set('domain', domain);
if (forceRefresh) {
url.searchParams.set('_forceRefresh', '1');
}
const res = await fetch(url, {
headers: { Authorization: `Token=${API_KEY}` },
});
if (!res.ok) {
throw new Error(`WHOIS ${res.status}: ${await res.text()}`);
}
return res.json();
}
function transferLocked(whois) {
const analysis = whois.statusAnalysis || {};
if (typeof analysis.transferLocked === 'boolean') {
return analysis.transferLocked;
}
const status = [].concat(whois.status || []).join(' ').toLowerCase();
return status.includes('clienttransferprohibited')
|| status.includes('servertransferprohibited');
}
async function verifyCriticalDomain(domain) {
// Pass 1: cheap cached check
const cached = await whoisLookup(domain);
if (transferLocked(cached)) {
return { domain, source: 'cache', ok: true, whois: cached };
}
// Pass 2: confirm with live data before paging on-call
const live = await whoisLookup(domain, { forceRefresh: true });
return {
domain,
source: 'live',
ok: transferLocked(live),
whois: live,
};
}
verifyCriticalDomain('example.com').then(console.log).catch(console.error);
Cache Freshness vs Rate Limits
Teams often mix two different failure modes. Keep them separate in logging and runbooks.
| Concern | Symptom | Fix |
|---|---|---|
| Stale data | Registrar/NS/status looks outdated after a known change | Selective_forceRefresh=1 |
| Throughput | HTTP 429, exhausted minute quota | Backoff, concurrency caps, see rate-limits guide |
| Monthly budget | Credits burn too fast | Default to cache; force-refresh only flagged domains |
Watch theRemaining-Requests response header on every call. Force-refresh does not bypass plan limits — it only changes freshness and credit cost per request.
FAQ
How long does WhoisJSON cache WHOIS responses?
The default cache TTL is about three hours. After expiry, the next request fetches live data and repopulates the cache.
Does _forceRefresh=1 always hit the live WHOIS server?
It requests the live path and costs 2 credits on eligible plans. Use it when you need current registry state — not as a default for every integration call.
Which plans can use force-refresh?
Force-refresh is available on Pro plans and above. See pricing for plan details and monthly quotas.
Does force-refresh work on DNS and SSL endpoints?
Should my monitor force-refresh every poll?
No. Poll on the default cache path. Force-refresh only domains that fail a policy check or that an analyst needs to confirm during an incident.
Is cache the same as rate limiting?
No. Cache controls data freshness. Rate limits control how many requests you may send per minute and per billing period. Handle both — retries for 429, selective force-refresh for staleness.
Build WHOIS Workflows Without Wasting Credits
Start with the 3-hour cache. Reserve _forceRefresh=1 for transfers, incidents and confirmations — then scale with a free API key.
Get API KeyRead the Docs