Developer reference
Typosquatting Detection
DomScan API: Detect typosquatting threats and similar domains that could be used for phishing or brand abuse.
Typosquatting Detection
Detect typosquatting threats and similar domains that could be used for phishing or brand abuse.
GET
/v1/typos
Query parameters
| Parameter | Type | Description |
|---|---|---|
| domain required | string | Domain to check for typosquatting variants |
| limit optional | number | Max permutations to check (default: 50) |
| check_registered optional |
boolean token
Allowed values
1true
Default
false
|
Checks which permutations are already registered, up to 50 domains. Off by default because it adds upstream lookups. |
Example response
{
"domain": "google.com",
"permutations_generated": 50,
"registered_typos": [
{
"domain": "gooogle.com",
"type": "repetition",
"risk": "high",
"registered": true
},
{
"domain": "googIe.com",
"type": "homoglyph",
"risk": "critical",
"registered": true
}
],
"threat_level": "critical",
"risk_summary": {
"critical": 2,
"high": 5,
"medium": 10,
"low": 8
}
}
Response fields
| Field | Type |
|---|---|
domain |
string |
name |
string |
tld |
string |
permutations_generated |
integer |
permutations_checked |
integer |
registered_typos[] |
object[] |
registered_typos[] |
object |
registered_typos[].classification |
object |
registered_typos[].classification.status |
string |
registered_typos[].classification.reason |
string |
registered_typos[].classification.evidence |
object |
registered_typos[].classification.evidence.source |
string |
registered_typos[].classification.evidence.method |
string |
registered_typos[].classification.evidence.observed_at |
string |
registered_typos[].classification.evidence.detail |
string |
registered_typos[].classification.checked_at |
string |
registered_typos[].domain |
string |
registered_typos[].name |
string |
registered_typos[].tld |
string |
registered_typos[].type |
string |
registered_typos[].risk |
string |
registered_typos[].description |
string |
registered_typos[].registered |
boolean |
registered_typos[].checked_at |
string |
available_typos |
integer |
unknown_typos |
integer |
risk_summary |
object |
risk_summary.critical |
integer |
risk_summary.high |
integer |
risk_summary.medium |
integer |
risk_summary.low |
integer |
threat_level |
string |
family_summary |
object |
family_summary.generated_by_type |
object |
family_summary.generated_by_risk |
object |
family_summary.registered_by_type |
object |
family_summary.registered_by_risk |
object |
family_summary.top_generated_family |
string | null |
family_summary.top_registered_family |
string | null |
family_summary.critical_or_high_generated_count |
integer |
family_summary.critical_or_high_registered_count |
integer |
family_summary.coverage_ratio |
number |
family_summary.checked_count |
integer |
family_summary.available_count |
integer |
family_summary.unknown_count |
integer |
family_summary.omitted_count |
integer |
family_summary.include_tld_swap |
boolean |
family_summary.requested_limit |
integer |
checked_at |
string |
check_duration_ms |
integer |
meta |
object |
meta.served_by |
string |
meta.cached |
boolean |
meta.query_time_ms |
integer |
meta.registration_check_requested |
boolean |
meta.registration_check_limit |
integer |
GET
/v1/typos/threats
Credits: 12
Query parameters
| Parameter | Type | required |
|---|---|---|
| domain | string | required |
| limit |
integer
Default
200
|
optional |
| include_tld_swap |
boolean
Default
true
|
optional |
Response fields
| Field | Type |
|---|---|
domain |
string |
name |
string |
tld |
string |
scan_summary |
object |
scan_summary.permutations_generated |
integer |
scan_summary.permutations_checked |
integer |
scan_summary.permutations_submitted |
integer |
scan_summary.definitive_results |
integer |
scan_summary.unknown_results |
integer |
scan_summary.omitted_results |
integer |
scan_summary.registered_count |
integer |
scan_summary.active_threats |
integer |
scan_summary.available_for_defensive |
integer |
scan_summary.check_limit |
integer |
scan_summary.coverage_truncated |
boolean |
threat_level |
string |
protection_score |
object |
protection_score.score |
integer |
protection_score.grade |
string |
protection_score.interpretation |
object |
protection_score.interpretation.score_meaning |
string |
protection_score.interpretation.factors |
string |
protection_score.interpretation.note |
string |
protection_score.vulnerabilities[] |
object[] |
protection_score.vulnerabilities[] |
object |
protection_score.vulnerabilities[].category |
string |
protection_score.vulnerabilities[].count |
integer |
protection_score.vulnerabilities[].risk |
string |
protection_score.vulnerabilities[].description |
string |
protection_score.recommendations[] |
string[] |
protection_score.factors |
object |
protection_score.factors.length_factor |
integer |
protection_score.factors.homoglyph_factor |
integer |
protection_score.factors.keyboard_factor |
integer |
protection_score.factors.tld_factor |
integer |
threats[] |
object[] |
threats[] |
object |
threats[].classification |
object |
threats[].classification.status |
string |
threats[].classification.reason |
string |
threats[].classification.evidence |
object |
threats[].classification.evidence.source |
string |
threats[].classification.evidence.method |
string |
threats[].classification.evidence.observed_at |
string |
threats[].classification.evidence.detail |
string |
threats[].classification.checked_at |
string |
threats[].domain |
string |
threats[].name |
string |
threats[].tld |
string |
threats[].type |
string |
threats[].risk |
string |
threats[].description |
string |
threats[].registered |
boolean |
threats[].checked_at |
string |
threats[].dns_active |
boolean |
threats[].has_website |
boolean |
threats[].has_mx |
boolean |
threats[].infrastructure |
object |
threats[].threat_indicators[] |
string[] |
threats[].threat_score |
integer |
defensive_opportunities[] |
object[] |
defensive_opportunities[] |
object |
defensive_opportunities[].domain |
string |
defensive_opportunities[].name |
string |
defensive_opportunities[].tld |
string |
defensive_opportunities[].type |
string |
defensive_opportunities[].risk |
string |
defensive_opportunities[].description |
string |
risk_breakdown |
object |
recommendations[] |
string[] |
checked_at |
string |
scan_duration_ms |
integer |
meta |
object |
meta.served_by |
string |
Example request
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/typos/threats?domain=example.com&limit=25&include_tld_swap=true"const response = await fetch("https://domscan.net/v1/typos/threats?domain=example.com&limit=25&include_tld_swap=true", {
headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);import os
import requests
response = requests.get(
"https://domscan.net/v1/typos/threats?domain=example.com&limit=25&include_tld_swap=true",
headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/typos/threats?domain=example.com&limit=25&include_tld_swap=true", nil)
if err != nil {
panic(err)
}
req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(resp.Status, string(data))
}require "json"
require "net/http"
uri = URI("https://domscan.net/v1/typos/threats?domain=example.com&limit=25&include_tld_swap=true")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))Example response
{
"domain": "example.com",
"name": "example",
"tld": "com",
"scan_summary": {
"permutations_generated": 109,
"permutations_checked": 75,
"permutations_submitted": 75,
"definitive_results": 71,
"unknown_results": 4,
"omitted_results": 0,
"registered_count": 2,
"active_threats": 2,
"available_for_defensive": 69,
"check_limit": 75,
"coverage_truncated": true
},
"threat_level": "high",
"protection_score": {
"score": 2,
"grade": "F",
"interpretation": {
"score_meaning": "Higher score = less vulnerable to typosquatting attacks",
"factors": "Domain length, homoglyph-susceptible characters, keyboard adjacency, TLD popularity, registered typosquats",
"note": "Short, well-known domains score lower because they have a larger inherent attack surface for typosquatting, not because they lack brand protection measures."
},
"vulnerabilities": [
{
"category": "homoglyph",
"count": 4,
"risk": "critical",
"description": "Contains 4 characters with visual lookalikes (e, a, l)"
},
{
"category": "keyboard",
"count": 5,
"risk": "high",
"description": "5 characters have many keyboard neighbors"
},
{
"category": "tld",
"count": 1,
"risk": "medium",
"description": ".com is a high-value TLD commonly targeted by typosquatters"
},
{
"category": "registered_high",
"count": 1,
"risk": "high",
"description": "1 high-risk typosquat domains are registered"
}
],
"recommendations": [
"Consider defensive registrations for common homoglyph variants",
"Consider registering example on alternative TLDs like .net, .org"
],
"factors": {
"length_factor": 90,
"homoglyph_factor": 68,
"keyboard_factor": 75,
"tld_factor": 80
}
},
"threats": [
{
"domain": "xeample.com",
"type": "transposition",
"risk": "high",
"description": "Swapped 'e' and 'x'",
"dns_active": true,
"has_website": true,
"has_mx": false,
"infrastructure": {
"nameservers": []
},
"threat_indicators": [
"Active DNS configuration",
"Domain resolves to IP (potential website)"
],
"threat_score": 75
},
{
"domain": "example.net",
"type": "tld-swap",
"risk": "medium",
"description": "TLD changed from .com to .net",
"dns_active": true,
"has_website": false,
"has_mx": false,
"infrastructure": {
"nameservers": []
},
"threat_indicators": [
"Active DNS configuration"
],
"threat_score": 40
}
],
"defensive_opportunities": [
{
"domain": "3xample.com",
"type": "homoglyph",
"risk": "critical"
},
{
"domain": "ex4mple.com",
"type": "homoglyph",
"risk": "critical"
},
{
"domain": "eaxmple.com",
"type": "transposition",
"risk": "high"
}
],
"risk_breakdown": {
"critical": [],
"high": [
{
"domain": "xeample.com",
"name": "xeample",
"tld": "com",
"type": "transposition",
"risk": "high",
"description": "Swapped 'e' and 'x'",
"registered": true,
"checked_at": "2026-10-09T10:15:29.000Z",
"dns_active": true,
"has_website": true,
"has_mx": false,
"infrastructure": {
"nameservers": []
},
"threat_indicators": [
"Active DNS configuration",
"Domain resolves to IP (potential website)"
],
"threat_score": 75
}
],
"medium": [
{
"domain": "example.net",
"name": "example",
"tld": "net",
"type": "tld-swap",
"risk": "medium",
"description": "TLD changed from .com to .net",
"registered": true,
"checked_at": "2026-10-09T10:15:29.000Z",
"dns_active": true,
"has_website": false,
"has_mx": false,
"infrastructure": {
"nameservers": []
},
"threat_indicators": [
"Active DNS configuration"
],
"threat_score": 40
}
],
"low": []
},
"recommendations": [
"2 registered typosquat domains have active DNS/websites. Monitor for phishing or brand abuse.",
"18 high-risk typosquat domains are available. Consider defensive registration to protect your brand.",
"Your domain has significant typosquatting vulnerability. Set up continuous monitoring for new registrations."
],
"checked_at": "2026-10-09T10:15:30.000Z",
"scan_duration_ms": 4120,
"meta": {
"served_by": "pop=MAD country=ES"
}
}
HTTP status codes
200OK400Bad Request401Unauthorized402Payment Required429Too Many Requests500Server Error
GET
/v1/typos/report
Credits: 18
Query parameters
| Parameter | Type | required |
|---|---|---|
| domain | string | required |
Response fields
| Field | Type |
|---|---|
domain |
string |
generated_at |
string |
executive_summary |
object |
executive_summary.threat_level |
string |
executive_summary.protection_grade |
string |
executive_summary.active_threats |
integer |
executive_summary.registered_typos |
integer |
executive_summary.immediate_action_required |
boolean |
threat_analysis |
object |
threat_analysis.domain |
string |
threat_analysis.name |
string |
threat_analysis.tld |
string |
threat_analysis.scan_summary |
object |
threat_analysis.scan_summary.permutations_generated |
integer |
threat_analysis.scan_summary.permutations_checked |
integer |
threat_analysis.scan_summary.permutations_submitted |
integer |
threat_analysis.scan_summary.definitive_results |
integer |
threat_analysis.scan_summary.unknown_results |
integer |
threat_analysis.scan_summary.omitted_results |
integer |
threat_analysis.scan_summary.registered_count |
integer |
threat_analysis.scan_summary.active_threats |
integer |
threat_analysis.scan_summary.available_for_defensive |
integer |
threat_analysis.scan_summary.check_limit |
integer |
threat_analysis.scan_summary.coverage_truncated |
boolean |
threat_analysis.threat_level |
string |
threat_analysis.protection_score |
object |
threat_analysis.protection_score.score |
integer |
threat_analysis.protection_score.grade |
string |
threat_analysis.protection_score.interpretation |
object |
threat_analysis.protection_score.interpretation.score_meaning |
string |
threat_analysis.protection_score.interpretation.factors |
string |
threat_analysis.protection_score.interpretation.note |
string |
threat_analysis.protection_score.vulnerabilities[] |
object[] |
threat_analysis.protection_score.vulnerabilities[] |
object |
threat_analysis.protection_score.vulnerabilities[].category |
string |
threat_analysis.protection_score.vulnerabilities[].count |
integer |
threat_analysis.protection_score.vulnerabilities[].risk |
string |
threat_analysis.protection_score.vulnerabilities[].description |
string |
threat_analysis.protection_score.recommendations[] |
string[] |
threat_analysis.protection_score.factors |
object |
threat_analysis.protection_score.factors.length_factor |
integer |
threat_analysis.protection_score.factors.homoglyph_factor |
integer |
threat_analysis.protection_score.factors.keyboard_factor |
integer |
threat_analysis.protection_score.factors.tld_factor |
integer |
threat_analysis.threats[] |
object[] |
threat_analysis.threats[] |
object |
threat_analysis.threats[].classification |
object |
threat_analysis.threats[].classification.status |
string |
threat_analysis.threats[].classification.reason |
string |
threat_analysis.threats[].classification.evidence |
object |
threat_analysis.threats[].classification.evidence.source |
string |
threat_analysis.threats[].classification.evidence.method |
string |
threat_analysis.threats[].classification.evidence.observed_at |
string |
threat_analysis.threats[].classification.evidence.detail |
string |
threat_analysis.threats[].classification.checked_at |
string |
threat_analysis.threats[].domain |
string |
threat_analysis.threats[].name |
string |
threat_analysis.threats[].tld |
string |
threat_analysis.threats[].type |
string |
threat_analysis.threats[].risk |
string |
threat_analysis.threats[].description |
string |
threat_analysis.threats[].registered |
boolean |
threat_analysis.threats[].checked_at |
string |
threat_analysis.threats[].dns_active |
boolean |
threat_analysis.threats[].has_website |
boolean |
threat_analysis.threats[].has_mx |
boolean |
threat_analysis.threats[].infrastructure |
object |
threat_analysis.threats[].threat_indicators[] |
string[] |
threat_analysis.threats[].threat_score |
integer |
threat_analysis.defensive_opportunities[] |
object[] |
threat_analysis.defensive_opportunities[] |
object |
threat_analysis.defensive_opportunities[].domain |
string |
threat_analysis.defensive_opportunities[].name |
string |
threat_analysis.defensive_opportunities[].tld |
string |
threat_analysis.defensive_opportunities[].type |
string |
threat_analysis.defensive_opportunities[].risk |
string |
threat_analysis.defensive_opportunities[].description |
string |
threat_analysis.risk_breakdown |
object |
threat_analysis.recommendations[] |
string[] |
threat_analysis.checked_at |
string |
threat_analysis.scan_duration_ms |
integer |
threat_analysis.meta |
object |
threat_analysis.meta.served_by |
string |
defensive_registration_priority |
object |
monitoring_recommendations[] |
string[] |
estimated_risk_exposure |
string |
meta |
object |
meta.served_by |
string |
meta.report_duration_ms |
integer |
Example request
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/typos/report?domain=example.com"const response = await fetch("https://domscan.net/v1/typos/report?domain=example.com", {
headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);import os
import requests
response = requests.get(
"https://domscan.net/v1/typos/report?domain=example.com",
headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/typos/report?domain=example.com", nil)
if err != nil {
panic(err)
}
req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(resp.Status, string(data))
}require "json"
require "net/http"
uri = URI("https://domscan.net/v1/typos/report?domain=example.com")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))Example response
{
"domain": "example.com",
"generated_at": "2026-08-27T12:00:00Z",
"executive_summary": {
"threat_level": "example",
"protection_grade": "example",
"active_threats": 1,
"registered_typos": 1,
"immediate_action_required": false
},
"threat_analysis": {
"domain": "example.com",
"scan_summary": {
"permutations_generated": 1,
"permutations_checked": 1,
"registered_count": 1,
"active_threats": 1,
"available_for_defensive": 1,
"permutations_submitted": 1,
"definitive_results": 1,
"unknown_results": 1,
"omitted_results": 1,
"check_limit": 1,
"coverage_truncated": false
},
"threat_level": "none",
"threats": [
{
"domain": "example.com",
"type": "domain",
"risk": "critical",
"dns_active": true,
"has_website": false,
"threat_indicators": [
"example"
],
"threat_score": 85,
"classification": {
"status": "present",
"evidence": {
"source": "rdap",
"method": "rdap_lookup",
"observed_at": "2026-08-27T12:00:00Z",
"detail": "example"
},
"checked_at": "2026-08-27T12:00:00Z",
"reason": "blocked"
},
"name": "example",
"tld": "com",
"description": "example",
"registered": false,
"checked_at": "2026-08-27T12:00:00Z",
"has_mx": false,
"infrastructure": {}
}
],
"checked_at": "2026-08-27T12:00:00Z",
"name": "example",
"tld": "com",
"protection_score": {
"score": 85,
"grade": "A",
"interpretation": {
"score_meaning": "example",
"factors": "example",
"note": "example"
},
"vulnerabilities": [
{
"category": "example",
"count": 1,
"risk": "critical",
"description": "example"
}
],
"recommendations": [
"example"
],
"factors": {
"length_factor": 1,
"homoglyph_factor": 1,
"keyboard_factor": 1,
"tld_factor": 1
}
},
"defensive_opportunities": [
{
"domain": "example.com",
"name": "example",
"tld": "com",
"type": "omission",
"risk": "critical",
"description": "example"
}
],
"risk_breakdown": {},
"recommendations": [
"example"
],
"scan_duration_ms": 1,
"meta": {
"served_by": "example"
}
},
"estimated_risk_exposure": "minimal",
"defensive_registration_priority": {},
"monitoring_recommendations": [
"example"
],
"meta": {
"served_by": "example",
"report_duration_ms": 1
}
}
HTTP status codes
200OK400Bad Request401Unauthorized402Payment Required429Too Many Requests500Server Error
GET
/v1/typos/quick
Credits: 6
Query parameters
| Parameter | Type | required |
|---|---|---|
| domain | string | required |
| limit |
integer
Default
100
|
optional |
Response fields
| Field | Type |
|---|---|
domain |
string |
registered_typos[] |
object[] |
registered_typos[] |
object |
registered_typos[].domain |
string |
registered_typos[].type |
string |
registered_typos[].risk |
string |
registered_typos[].description |
string |
registered_typos[].classification |
object |
registered_typos[].classification.status |
string |
registered_typos[].classification.reason |
string |
registered_typos[].classification.evidence |
object |
registered_typos[].classification.evidence.source |
string |
registered_typos[].classification.evidence.method |
string |
registered_typos[].classification.evidence.observed_at |
string |
registered_typos[].classification.evidence.detail |
string |
registered_typos[].classification.checked_at |
string |
count |
integer |
threat_level |
string |
coverage |
object |
coverage.requested |
integer |
coverage.definitive |
integer |
coverage.unknown |
integer |
coverage.omitted |
integer |
checked_at |
string |
scan_duration_ms |
integer |
meta |
object |
meta.served_by |
string |
Example request
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/typos/quick?domain=example.com&limit=25"const response = await fetch("https://domscan.net/v1/typos/quick?domain=example.com&limit=25", {
headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);import os
import requests
response = requests.get(
"https://domscan.net/v1/typos/quick?domain=example.com&limit=25",
headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/typos/quick?domain=example.com&limit=25", nil)
if err != nil {
panic(err)
}
req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(resp.Status, string(data))
}require "json"
require "net/http"
uri = URI("https://domscan.net/v1/typos/quick?domain=example.com&limit=25")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))Example response
{
"domain": "example.com",
"registered_typos": [
{
"domain": "xeample.com",
"type": "transposition",
"risk": "high",
"description": "Swapped 'e' and 'x'"
},
{
"domain": "example.net",
"type": "tld-swap",
"risk": "medium",
"description": "TLD changed from .com to .net"
}
],
"count": 2,
"threat_level": "high",
"coverage": {
"requested": 98,
"definitive": 92,
"unknown": 6,
"omitted": 0
},
"checked_at": "2026-10-09T10:15:30.000Z",
"scan_duration_ms": 2840,
"meta": {
"served_by": "pop=MAD country=ES"
}
}
HTTP status codes
200OK400Bad Request401Unauthorized402Payment Required429Too Many Requests500Server Error
GET
/v1/idn
Credits: 1
Query parameters
| Parameter | Type | required |
|---|---|---|
| domain | string | required |
Response fields
| Field | Type |
|---|---|
input |
string |
outcome |
string |
unicode |
string |
ascii |
string |
is_idn |
boolean |
valid |
boolean |
errors[] |
string[] |
labels[] |
object[] |
labels[] |
object |
labels[].unicode |
string |
labels[].ascii |
string |
labels[].is_idn |
boolean |
labels[].scripts[] |
string[] |
labels[].mixed_script |
boolean |
labels[].has_invisible |
boolean |
labels[].confusable_characters[] |
object[] |
labels[].confusable_characters[] |
object |
labels[].confusable_characters[].char |
string |
labels[].confusable_characters[].codepoint |
string |
labels[].confusable_characters[].script |
string |
labels[].confusable_characters[].looks_like |
string |
skeleton |
string |
risk |
object |
risk.level |
string |
risk.reasons[] |
string[] |
tld |
object |
tld.label |
string |
tld.ascii |
string |
tld.is_idn |
boolean |
checked_at |
string |
caveats[] |
string[] |
Example request
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/idn?domain=xn--80ak6aa92e.com"const response = await fetch("https://domscan.net/v1/idn?domain=xn--80ak6aa92e.com", {
headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);import os
import requests
response = requests.get(
"https://domscan.net/v1/idn?domain=xn--80ak6aa92e.com",
headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/idn?domain=xn--80ak6aa92e.com", nil)
if err != nil {
panic(err)
}
req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(resp.Status, string(data))
}require "json"
require "net/http"
uri = URI("https://domscan.net/v1/idn?domain=xn--80ak6aa92e.com")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))Example response
{
"input": "xn--80ak6aa92e.com",
"outcome": "analyzed",
"unicode": "аррӏе.com",
"ascii": "xn--80ak6aa92e.com",
"is_idn": true,
"valid": true,
"errors": [],
"labels": [
{
"unicode": "аррӏе",
"ascii": "xn--80ak6aa92e",
"is_idn": true,
"scripts": [
"Cyrillic"
],
"mixed_script": false,
"has_invisible": false,
"confusable_characters": [
{
"char": "а",
"codepoint": "U+0430",
"script": "Cyrillic",
"looks_like": "a"
},
{
"char": "р",
"codepoint": "U+0440",
"script": "Cyrillic",
"looks_like": "p"
},
{
"char": "р",
"codepoint": "U+0440",
"script": "Cyrillic",
"looks_like": "p"
},
{
"char": "ӏ",
"codepoint": "U+04CF",
"script": "Cyrillic",
"looks_like": "l"
},
{
"char": "е",
"codepoint": "U+0435",
"script": "Cyrillic",
"looks_like": "e"
}
]
},
{
"unicode": "com",
"ascii": "com",
"is_idn": false,
"scripts": [
"Latin"
],
"mixed_script": false,
"has_invisible": false,
"confusable_characters": []
}
],
"skeleton": "apple.com",
"risk": {
"level": "high",
"reasons": [
"whole_script_confusable",
"idn_label"
]
},
"tld": {
"label": "com",
"ascii": "com",
"is_idn": false
},
"checked_at": "2026-10-09T10:15:30.000Z",
"caveats": [
"partial_confusable_table"
]
}
HTTP status codes
200OK400Bad Request401Unauthorized402Payment Required429Too Many Requests