Every live tool is a JSON endpoint under https://api.ferrlens.com. Send a POST with a JSON
body, get JSON back. No authentication: anonymous requests share a per-IP budget, see
Rate limits.
curl -X POST https://api.ferrlens.com/v1/dns/lookup \
-H 'content-type: application/json' \
-d '{"domain":"example.com"}'
Errors
A failed request returns a non-2xx status and a body with a stable code:
{ "code": "INVALID_STRATEGY", "message": "strategy must be 'mobile' or 'desktop'" }
Branch on code, not on message. A 429 carries RATE_LIMITED and a Retry-After header.
URLs you submit must be public. Addresses that resolve to private or internal ranges are rejected.
DNS
| Endpoint | Request | Response |
|---|---|---|
POST /v1/dns/lookup |
domain |
domain, records (kind, records[]), total |
POST /v1/dns/propagation |
domain, kind (default A) |
domain, kind, distinct_answers, hits[] |
POST /v1/dns/reverse |
ip |
ip, hostnames[] |
kind for propagation is one of A, AAAA, MX, TXT, NS, CNAME, SOA. Each entry of
hits is one public resolver: resolver, resolver_label, resolver_ip, timings_ms,
records, error. When distinct_answers has a single entry, every resolver agrees.
| Endpoint | Request | Response |
|---|---|---|
POST /v1/email/spf-dmarc |
domain |
spf, dmarc, dkim_selectors[], score, notes[] |
POST /v1/email/blacklist |
target (domain or IP) |
target, resolved_ip, checked, listed, errored, entries[] |
POST /v1/email/verify |
email |
syntax_valid, local_part, domain, disposable, role_based, mx[], has_mx |
SEO and web
| Endpoint | Request | Response |
|---|---|---|
POST /v1/seo/check |
url, strategy (mobile default, or desktop) |
url, fetched_at, scores, core_web_vitals, notes[], findings[] |
POST /v1/seo/check/stream |
same as above | server-sent events |
POST /v1/seo/robots |
domain, user_agent, test_path |
url, status, raw, groups[], sitemaps[], matched_agent, test_result |
POST /v1/seo/sitemap |
url |
url, status, is_index, url_count, sample[], children[], warnings[] |
POST /v1/web/meta |
url |
url, final_url, title, entries[], counts |
POST /v1/web/og-preview |
url |
url, final_url, card, warnings[] |
POST /v1/web/mixed-content |
url |
url, final_url, is_https, mixed[], total |
POST /v1/web/cors |
url, origin, method (default GET) |
preflight, actual, checks[] |
POST /v1/web/ct-search |
domain |
domain, total, unique_sans, certificates[] |
POST /v1/http/headers |
url |
url, final_url, status, headers, timings_ms, redirects[] |
POST /v1/http/sec-headers |
url |
url, final_url, status, total_score, grade, checks[] |
scores holds performance, seo, accessibility and best_practices, each a number or
null. SEO results are cached for 24 hours per URL and strategy.
The stream variant sends accepted first, then vitals, scores and notes as they become
available, and ends with done or error. A cached result arrives as one cached event
followed by done.
Link check
POST /v1/link-check crawls a site from url and reports the status of every link it finds.
| Field | Default | Limits |
|---|---|---|
url |
required | |
max_depth |
2 |
clamped to 1 to 3 |
max_pages |
200 |
clamped to 10 to 500 |
The crawl respects robots.txt, waits between requests, and stops after 60 seconds. The
response lists the crawled pages and a summary with total, broken, redirects, ok,
external, blocked_by_robots, blocked and unreachable.
Shares
POST /v1/shares, GET /v1/shares/{id} and DELETE /v1/shares/{id} are covered in
Share links.