Bulk Domain Lookup API — Check 10 Domains in One Request
February 28, 2026
You manage 50 domains and need to check which ones expire in the next 30 days. With single-domain lookups, that's 50 HTTP round-trips — 50 separate connections, 50 response parses, and separate error handling for each.
The RDAP API bulk endpoint takes up to 10 domains per request and resolves them concurrently server-side. 50 domains becomes 5 requests instead of 50 — and each one returns normalized JSON for every domain in a single response.
Why bulk instead of parallel single calls?
You could fire 10 single-domain requests in parallel with Promise.all() or asyncio.gather(). That works, but bulk gives you:
- One HTTP round-trip instead of ten — less connection overhead, fewer sockets, simpler timeout handling
- Server-side concurrency — the API resolves all 10 domains in parallel against upstream RDAP servers, handling per-server rate limits and retries internally
- Atomic response — one JSON object with a
summarytelling you exactly how many succeeded and failed. No need to merge 10 separate responses yourself
Quick start
curl -X POST https://rdapapi.io/api/v1/domains/bulk \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domains": ["google.com", "github.com", "example.net"]}'
Response:
{
"results": [
{
"domain": "google.com",
"status": "success",
"data": {
"domain": "google.com",
"registrar": {
"name": "MarkMonitor Inc.",
"iana_id": "292",
"abuse_email": "[email protected]"
},
"dates": {
"registered": "1997-09-15T04:00:00Z",
"expires": "2028-09-14T04:00:00Z",
"updated": "2019-09-09T15:39:04Z"
},
"nameservers": ["ns1.google.com", "ns2.google.com"],
"dnssec": false
}
},
{
"domain": "github.com",
"status": "success",
"data": { "..." : "..." }
},
{
"domain": "example.net",
"status": "success",
"data": { "..." : "..." }
}
],
"summary": {
"total": 3,
"successful": 3,
"failed": 0
}
}
Each domain is resolved independently — if one fails, the others still return data.
Practical example: domain expiration monitor
Here's a script that checks a list of domains and flags any expiring within 30 days. Run it as a daily cron job.
from rdapapi import RdapApi
from datetime import datetime, timezone
DOMAINS = [
"mycompany.com", "mycompany.io", "mycompany.dev",
"myproduct.com", "myproduct.app",
"mybrand.org", "mybrand.net", "mybrand.co",
]
client = RdapApi("YOUR_API_KEY")
now = datetime.now(timezone.utc)
# Bulk accepts 10 domains max — batch if you have more
for i in range(0, len(DOMAINS), 10):
results = client.domains.bulk(DOMAINS[i:i + 10])
for r in results.results:
if r.status != "success":
print(f"WARNING: {r.domain} — lookup failed ({r.error})")
continue
expires = datetime.fromisoformat(r.data.dates.expires)
days_left = (expires - now).days
if days_left <= 30:
print(f"URGENT: {r.domain} expires in {days_left} days")
elif days_left <= 90:
print(f"SOON: {r.domain} expires in {days_left} days")
import { RdapApi } from "rdapapi";
const DOMAINS = [
"mycompany.com", "mycompany.io", "mycompany.dev",
"myproduct.com", "myproduct.app",
"mybrand.org", "mybrand.net", "mybrand.co",
];
async function checkExpirations() {
const client = new RdapApi("YOUR_API_KEY");
const now = new Date();
// Bulk accepts 10 domains max — batch if you have more
for (let i = 0; i < DOMAINS.length; i += 10) {
const { results } = await client.domains.bulk(DOMAINS.slice(i, i + 10));
for (const r of results) {
if (r.status !== "success") {
console.log(`WARNING: ${r.domain} — lookup failed (${r.error})`);
continue;
}
const expires = new Date(r.data.dates.expires);
const daysLeft = Math.floor((expires - now) / 86400000);
if (daysLeft <= 30) {
console.log(`URGENT: ${r.domain} expires in ${daysLeft} days`);
} else if (daysLeft <= 90) {
console.log(`SOON: ${r.domain} expires in ${daysLeft} days`);
}
}
}
}
checkExpirations();
A few things to note about the bulk endpoint:
- 10 domains per request. If you have more, batch in chunks of 10 — both examples above do this. There's no delay needed between requests. We cap at 10 to keep response times predictable (uncached domains require upstream RDAP fetches)
- Duplicate domains in the same request are automatically deduplicated (case-insensitive)
- Responses are cached for 24 hours. If you poll the same domains daily, you'll mostly hit cache — fast responses, but each domain still counts as one lookup against your quota. The trade-off is predictable billing: you always know the cost upfront
Registrar follow-through
For thin registries like .com and .net, the registry only stores basic data. The registrar (GoDaddy, Cloudflare, etc.) holds contacts and entity details on a separate RDAP server.
Set follow: true to automatically follow the registrar link and merge both responses:
curl -X POST https://rdapapi.io/api/v1/domains/bulk \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domains": ["google.com", "github.com"], "follow": true}'
With follow, the entities field includes registrant details when available:
{
"entities": {
"registrant": {
"organization": "Google LLC",
"country_code": "US"
}
}
}
Without it, entities is typically empty for .com domains because VeriSign's registry doesn't store contact data. See our RDAP vs WHOIS guide for background on thin vs. thick registries.
Error handling
The bulk endpoint always returns HTTP 200 — even if individual domains fail. Check each result's status field:
{
"results": [
{
"domain": "google.com",
"status": "success",
"data": { "..." : "..." }
},
{
"domain": "invalid..com",
"status": "error",
"error": "invalid_domain",
"message": "The provided domain name is not valid."
}
],
"summary": {
"total": 2,
"successful": 1,
"failed": 1
}
}
One bad domain doesn't break the others — no retry logic needed for the whole batch.
HTTP-level errors (these affect the entire request):
| Code | Meaning |
|---|---|
401 |
Missing or invalid API key |
403 |
Plan doesn't support bulk (Starter) — upgrade here |
422 |
Validation error (>10 domains, empty array) |
429 |
Rate limit or monthly quota exceeded |
Pricing
Bulk requires a Pro ($49/mo, 200k lookups) or Business ($199/mo, 1M lookups) plan. Starter plans return a 403.
Each domain in a bulk request counts as one lookup against your monthly quota — a 10-domain request uses 10 lookups. All plans come with a free 7-day trial.
What's next
- Full API reference — interactive endpoint documentation
- Check domain expiration with code — single-domain expiration checks in 5 languages
- RDAP vs WHOIS — why RDAP returns better data than WHOIS
- Get your API key — free 7-day trial on all plans