API Integration Guide
Learn how to integrate Have I Been Squatted’s API into your security workflows.
Authentication
Section titled “Authentication”API tokens are created in the platform. Go to Settings -> API Keys, create a token, select scopes, and optionally set an expiration. The token is only shown once after creation.
If you previously used a legacy JWT, rotate to a platform API token. Legacy /v1/squat and /v1/nxdomain routes exist for older JWT integrations; new tokens should use the /v1/lookup/* and /v1/analyze/* routes.
Scopes
Section titled “Scopes”API tokens are scoped. Requests made with a token must include the scope required by the endpoint.
| Scope | Description | Example endpoints |
|---|---|---|
lookup:squat | Look up typosquatted domains | GET /v1/lookup/squat/{domain} |
lookup:nxdomain | Look up non-existent domains | GET /v1/lookup/nxdomain/{domain} |
analyze | Analyze domains for threats | GET /v1/analyze/{domain} |
ct | Certificate Transparency lookups | GET /v1/ct/search, GET /v1/ct/hydrate |
Expiration Policy
Section titled “Expiration Policy”When creating a token, you can choose a 7, 30, 60, or 90 day expiration, or select No expiration. Expired or revoked tokens stop working immediately, and the full token value is only shown once at creation.
Making Requests
Section titled “Making Requests”We currently expose these endpoint families:
https://api.haveibeensquatted.com/v1/lookup/squat/{domain}- Lookup a single domain for squattinghttps://api.haveibeensquatted.com/v1/lookup/nxdomain/{domain}- Lookup a single domain for unregistered domains (NXDOMAIN)https://api.haveibeensquatted.com/v1/analyze/{domain}- Analyze a single domain for threatshttps://api.haveibeensquatted.com/v1/ct/*- Certificate Transparency search and hydration
Request Format
Section titled “Request Format”export HIBS_API_TOKEN="YOUR_API_TOKEN"domain="example.com"
curl -N "https://api.haveibeensquatted.com/v1/lookup/squat/$domain" \ -H "Authorization: Bearer $HIBS_API_TOKEN"Handling Streaming Responses
Section titled “Handling Streaming Responses”Lookup and analyze endpoints use HTTP/2 streaming to provide real-time results. Here are examples of how to handle the streamed JSON responses:
import httpximport json
async def lookup_domain(domain: str, api_token: str): async with httpx.AsyncClient() as client: url = f"https://api.haveibeensquatted.com/v1/lookup/squat/{domain}" headers = {"Authorization": f"Bearer {api_token}"}
async with client.stream("GET", url, headers=headers) as response: async for line in response.aiter_lines(): if line.strip(): result = json.loads(line) # Handle each result as it arrives if result["op"] == "Meta": print(f"Progress: {result['data']['data'][0]}/{result['data']['data'][1]}") elif result["op"] == "GeoIp": print(f"Found IP in {result['data']['country']['iso_code']}")async function lookupDomain(domain, apiToken) { const response = await fetch(`https://api.haveibeensquatted.com/v1/lookup/squat/${domain}`, { method: 'GET', headers: { 'Authorization': `Bearer ${apiToken}`, }, });
const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = '';
while (true) { const { done, value } = await reader.read(); if (done) break;
buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || '';
for (const line of lines) { if (line.trim()) { const result = JSON.parse(line); // Handle each result as it arrives if (result.op === 'Meta') { console.log(`Progress: ${result.data.data[0]}/${result.data.data[1]}`); } } } }}package main
import ( "bufio" "encoding/json" "fmt" "net/http")
func lookupDomain(domain, apiToken string) error { url := fmt.Sprintf("https://api.haveibeensquatted.com/v1/lookup/squat/%s", domain) req, err := http.NewRequest("GET", url, nil) if err != nil { return err }
req.Header.Add("Authorization", "Bearer "+apiToken)
resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body) for scanner.Scan() { line := scanner.Text() if line == "" { continue }
var result map[string]interface{} if err := json.Unmarshal([]byte(line), &result); err != nil { return err }
// Handle each result as it arrives if result["op"] == "Meta" { data := result["data"].(map[string]interface{}) progress := data["data"].([]interface{}) fmt.Printf("Progress: %v/%v\n", progress[0], progress[1]) } }
return scanner.Err()}Processing Results
Section titled “Processing Results”Here are some examples of processing the JSON output using jq:
# Find domains hosted on specific ASNsjq '.[] | select(.ips[].asn.number == 16509)' results.json
# List domains with suspicious hosting locationsjq '.[] | select(.ips[].country.iso_code != "US")' results.json
# Extract all unique ASNsjq '.[] | .ips[].asn.organization' results.json | sort | uniqFor the complete JSON schema reference, see our JSON Schema Documentation.