Back to Learning Hub
DEVELOPER GUIDE September 3, 2026 · 12 min read · 3.2K/mo

DomainScan API + MCP: The Developer Guide

One JSON envelope across every tool. One API key. One MCP server. Everything the platform runs on is the same interface your code and your AI agent can hit — WHOIS, DNS, DMARC, SSL, blacklist, subdomain enumeration. Copy-paste examples in 8 languages, MCP config for Claude Code and Cursor, and the credit model explained in one page.

D
DomainScan Team
DomainScan
Share
DEVELOPER GUIDE

DomainScan ships two developer surfaces on the same backend: a JSON REST API and a Model Context Protocol (MCP) server. Both expose every tool on the platform — WHOIS, DNS, SSL, DMARC, blacklist, subdomain enumeration, IP intelligence, security headers, ~50 tools total — as callable primitives. Same authentication, same rate limits, same JSON envelope. The only difference is which client is calling.

This guide walks through the API in eight languages, the MCP server setup for Claude Code and Cursor, the shared JSON envelope, the credit model, and the error and retry contract. Everything you need to integrate is here; the help centre has the running quickstarts if you prefer step-by-step.

The Shared JSON Envelope

Every DomainScan API response uses the same top-level shape. Consistency across 50 tools makes client code portable:

{
  "stats": {
    "domain_age_days": 8542,
    "until_expiry_days": 145,
    "health_score": 92,
    "nameservers": 4
  },
  "Summary": {
    "domain": "example.com",
    "registrar": "MarkMonitor Inc.",
    "created": "2003-04-01T00:00:00Z",
    "expires": "2026-04-01T00:00:00Z",
    "status": ["clientDeleteProhibited", "clientTransferProhibited"]
  },
  "Registration": { "..." : "..." },
  "Nameservers": { "..." : "..." },
  "Traffic":     { "..." : "..." },
  "RawData":     { "..." : "..." }
}

Each tool populates the sections relevant to it. A WHOIS call returns Summary and Registration; an SSL call returns Chain, Security, and Raw. Every response is JSON, every timestamp is ISO 8601 UTC, every score is on a 0–100 scale. See the DNS glossary entry for the underlying record vocabulary the envelope references.

Authentication

One header, one bearer token:

Authorization: Bearer YOUR_API_KEY

API keys are provisioned in the DomainScan dashboard. Free tier gets one key with 500 credits/month and access to 8 tools. Pro tier gets multiple scoped keys with 20,000 credits/month and access to 40+ tools. Every request is logged with the key ID for audit and usage-attribution purposes.

Copy-Paste Examples — Eight Languages

Every example below runs a WHOIS lookup for example.com and prints the registrar. The pattern extends to every endpoint by swapping the path and payload.

cURL

curl -X POST https://api.domainscan.in/api/v1/domain/lookup \
  -H "Authorization: Bearer $DOMAINSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com"}'

Python (requests)

import os
import requests

response = requests.post(
    "https://api.domainscan.in/api/v1/domain/lookup",
    headers={"Authorization": f"Bearer {os.environ['DOMAINSCAN_API_KEY']}"},
    json={"domain": "example.com"},
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data["Summary"]["registrar"])

Node.js (fetch, Node 20+)

const response = await fetch("https://api.domainscan.in/api/v1/domain/lookup", {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${process.env.DOMAINSCAN_API_KEY}`,
        "Content-Type": "application/json",
    },
    body: JSON.stringify({domain: "example.com"}),
});
const data = await response.json();
console.log(data.Summary.registrar);

Go (net/http)

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

func main() {
    body, _ := json.Marshal(map[string]string{"domain": "example.com"})
    req, _ := http.NewRequest("POST",
        "https://api.domainscan.in/api/v1/domain/lookup",
        bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("DOMAINSCAN_API_KEY"))
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()

    var data map[string]any
    json.NewDecoder(resp.Body).Decode(&data)
    fmt.Println(data["Summary"].(map[string]any)["registrar"])
}

PHP (Guzzle)

<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();
$response = $client->post('https://api.domainscan.in/api/v1/domain/lookup', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('DOMAINSCAN_API_KEY'),
        'Content-Type'  => 'application/json',
    ],
    'json' => ['domain' => 'example.com'],
]);
$data = json_decode($response->getBody(), true);
echo $data['Summary']['registrar'];

Ruby (Net::HTTP)

require 'net/http'
require 'json'

uri = URI('https://api.domainscan.in/api/v1/domain/lookup')
req = Net::HTTP::Post.new(uri, {
    'Authorization' => "Bearer #{ENV['DOMAINSCAN_API_KEY']}",
    'Content-Type'  => 'application/json',
})
req.body = { domain: 'example.com' }.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(req)
end
puts JSON.parse(response.body)['Summary']['registrar']

Rust (reqwest)

use std::env;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api.domainscan.in/api/v1/domain/lookup")
        .bearer_auth(env::var("DOMAINSCAN_API_KEY")?)
        .json(&json!({ "domain": "example.com" }))
        .send().await?
        .json::<serde_json::Value>().await?;
    println!("{}", response["Summary"]["registrar"]);
    Ok(())
}

Java (java.net.http, Java 11+)

import java.net.URI;
import java.net.http.*;

public class DomainScanExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create("https://api.domainscan.in/api/v1/domain/lookup"))
            .header("Authorization", "Bearer " + System.getenv("DOMAINSCAN_API_KEY"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString("{\"domain\":\"example.com\"}"))
            .build();
        HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println(res.body());
    }
}

The Endpoint Map

Every tool on the platform is a REST endpoint under the same base. Categorised:

Domain intelligence/domain/lookup (WHOIS/RDAP), /domain/dns, /domain/ns, /domain/propagation, /domain/trust, /domain/snapshot, /domain/analytics, /domain/spf, /domain/dmarc, /domain/dkim

Network and IP/ip/lookup, /ip/myip, /ip/ping, /ip/port, /ip/subnet, /ip/traceroute, /ip/reverse

Security/security/ssl-info, /security/ssl-chain, /security/blacklist, /security/mac-info, /security/headers

Developer utilities/developer/hash

Analytics/analytics/global, /analytics/tool, /analytics/audit

AI (Prism)/ai/prism/chat, /ai/prism/tools

Every one of these follows the same contract: POST with a JSON body, receive a JSON envelope with the same top-level structure.

MCP — Model Context Protocol

MCP is an open specification from Anthropic that lets AI clients call external tools with a standardised contract. DomainScan’s MCP server exposes every platform tool as a native MCP tool. Point Claude Desktop, Claude Code, or Cursor at the server and the AI calls the tools directly from natural language:

User: What's the DMARC posture of paypal.com?
AI: [calls domain_dmarc tool] → paypal.com is at p=reject with rua reporting to
    [email protected]. Fully aligned SPF and DKIM. Grade A. ...

No scraping, no wrapper code, no JSON parsing on the client side. For the wider context of why MCP matters for AI agents specifically, see the MCP domain intelligence overview.

MCP Config — Claude Desktop and Claude Code

Add DomainScan to your claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "domainscan": {
      "command": "npx",
      "args": ["-y", "@domainscan/mcp"],
      "env": {
        "DOMAINSCAN_API_KEY": "YOUR_API_KEY_HERE"
      }
    }
  }
}

Restart Claude Desktop. The DomainScan tools appear in the tool picker and can be invoked in-conversation.

For Claude Code, the same block works in ~/.claude/mcp_config.json. See the MCP quickstart for a step-by-step.

MCP Config — Cursor

Cursor’s MCP support ships with a similar config in Cursor Settings → MCP:

{
  "mcpServers": {
    "domainscan": {
      "command": "npx",
      "args": ["-y", "@domainscan/mcp"],
      "env": {
        "DOMAINSCAN_API_KEY": "YOUR_API_KEY_HERE"
      }
    }
  }
}

Same pattern, same tools. Cursor picks them up as callable functions inside its chat and agent modes.

Common Flows

Full Domain Audit in Under a Minute

One key, five calls, complete posture readout:

import os, requests

DOMAIN = "example.com"
BASE = "https://api.domainscan.in/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['DOMAINSCAN_API_KEY']}"}

for path in ["/domain/lookup", "/domain/dns", "/domain/dmarc",
             "/security/ssl-info", "/security/blacklist"]:
    r = requests.post(f"{BASE}{path}", headers=HEADERS,
                      json={"domain": DOMAIN}, timeout=30)
    print(path, r.json().get("stats", {}))

Roughly 25–40 credits total on Pro tier. Under 5 seconds wall time. Full posture across WHOIS, DNS, DMARC, SSL, and blacklist.

DMARC Enforcement Check

For AP or vendor-management workflows, the single call that matters:

curl -X POST https://api.domainscan.in/api/v1/domain/dmarc \
  -H "Authorization: Bearer $DOMAINSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "vendor.com"}'

Response includes the parsed policy tags (p, sp, rua, pct, adkim, aspf) and an enforcement grade. Wire it into vendor-risk scoring and get a monthly report of every vendor whose posture drifted from p=reject.

Subdomain Enumeration and Takeover Risk

For attack-surface management:

curl -X POST https://api.domainscan.in/api/v1/security/subdomains \
  -H "Authorization: Bearer $DOMAINSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "sources": ["ct", "brute"]}'

Returns every discoverable subdomain plus per-host liveness, TLS status, and dangling-CNAME risk flag. Pro tier and above.

Rate Limits and Credits

Rate limits (requests per minute): Free 60, Starter 300, Pro 600, Business 1,200, Enterprise negotiable. Enforced per API key. When exceeded, the API returns HTTP 429 with a Retry-After header.

Credit costs per call (typical): simple tools like hash/base64 = 1 credit. Standard tools (WHOIS, DNS, IP lookup, SSL) = 5–10 credits. Heavier tools (subdomain enumeration, DMARC RUA aggregation, propagation across 30+ resolvers) = 25–100 credits. Credit consumption is included in the response header X-Credits-Consumed; remaining monthly balance is in X-Credits-Remaining.

Monthly credit pool: Free 500, Starter 10,000, Pro 20,000, Business 100,000, Enterprise custom. Refreshes on billing anniversary. Overage billing is opt-in in Settings (off by default) so you never see a surprise bill.

Error Contract

Every non-2xx response is a JSON object with a stable shape:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "60 requests per minute exceeded on this key.",
    "retry_after_seconds": 30,
    "request_id": "req_01HXYZ..."
  }
}

Documented codes include INVALID_INPUT, AUTH_FAILED, TIER_INSUFFICIENT, RATE_LIMIT_EXCEEDED, CREDIT_EXHAUSTED, UPSTREAM_TIMEOUT, and INTERNAL_ERROR. Always include the request_id in any support ticket — it lets us trace the specific call through the pipeline in under a minute.

Recommended retry pattern: exponential backoff starting at 500ms, capped at 30s, with jitter, honouring Retry-After when present. Do not retry INVALID_INPUT or AUTH_FAILED — those are client-side errors and re-issuing the same request wastes credits.

Where DomainScan Fits Your Stack

Three canonical integration points:

  1. CI/CD — run a DMARC and SSL check on every deployment. Fail the deploy if a customer-facing subdomain regresses.
  2. Vendor risk — nightly job that scores every vendor of record on DMARC, SSL, and blacklist posture. Feeds a quarterly vendor-risk report to procurement.
  3. AI agents via MCP — expose the tools to Claude, Cursor, or your own MCP client so natural-language queries about domain security resolve directly against fresh data.

Free tier is enough to pilot every integration on a single domain before rolling out. Get an API key (free, no credit card, 500 credits/month) and start with a single WHOIS call.

Frequently Asked Questions

What is the DomainScan API base URL?

The production base URL is https://api.domainscan.in/api/v1. Every endpoint returns JSON with the same envelope: a top-level object containing stats, Summary, and per-tab result sections. Auth is via an Authorization: Bearer <API_KEY> header. Free-tier keys work out of the box on 8 tools and 500 credits per month; higher tiers unlock more tools and credit pools.

What is MCP and why does DomainScan ship an MCP server?

MCP (Model Context Protocol) is an open specification from Anthropic that lets AI clients like Claude Desktop, Claude Code, and Cursor call external tools with a consistent contract. DomainScan’s MCP server exposes every platform tool as a native function the AI can call — no scraping, no hand-rolled JSON parsing, no API wrapper code. Point Claude at the server, ask for a WHOIS or a DMARC audit in natural language, and the AI calls the tool directly.

How is the credit model calculated?

Each tool call consumes a fixed number of API credits per the manifest. Simple tools (hash, base64) cost 1 credit. Standard tools (WHOIS, DNS, IP lookup) cost 5–10 credits. Heavier tools (subdomain enumeration, DMARC RUA aggregation, propagation across 30+ resolvers) cost 25–100 credits. Your monthly credit pool refreshes on your billing anniversary; overage billing is opt-in and priced at $0.50–$2 per 1,000 credits depending on tier.

Which languages have official code examples?

cURL, Python (requests), Node.js (fetch), Go (net/http), PHP (Guzzle), Ruby (Net::HTTP), Rust (reqwest), and Java (java.net.http). Every example hits the same endpoint with the same auth header — the API is designed to be language-agnostic and requires nothing more than an HTTPS client and a JSON parser.

What is the rate limit?

Rate limits are tier-based: Free tier at 60 req/min, Starter at 300 req/min, Pro at 600 req/min, Business at 1,200 req/min, and Enterprise negotiable. Rate limits are enforced per API key. When you hit the limit, the API returns HTTP 429 with a Retry-After header — the recommended pattern is exponential backoff starting at the header value.

Can I use the API from a browser or does it require a backend?

CORS is enabled for calls from browsers only when you use a scoped key configured with an allowed-origin. The default API key format is server-only — do not embed it in JavaScript shipped to end users. For client-side use, generate a scoped key in the dashboard, set its allowed origins, and treat it like a public token.

Sources

Common Questions

01

What is the DomainScan API base URL?

The production base URL is `https://api.domainscan.in/api/v1`. Every endpoint returns JSON with the same envelope: a top-level object containing `stats`, `Summary`, and per-tab result sections. Auth is via an `Authorization: Bearer <API_KEY>` header. Free-tier keys work out of the box on 8 tools and 500 credits per month; higher tiers unlock more tools and credit pools.

02

What is MCP and why does DomainScan ship an MCP server?

MCP (Model Context Protocol) is an open specification from Anthropic that lets AI clients like Claude Desktop, Claude Code, and Cursor call external tools with a consistent contract. DomainScan's MCP server exposes every platform tool as a native function the AI can call — no scraping, no hand-rolled JSON parsing, no API wrapper code. Point Claude at the server, ask for a WHOIS or a DMARC audit in natural language, and the AI calls the tool directly.

03

How is the credit model calculated?

Each tool call consumes a fixed number of API credits per the manifest. Simple tools (hash, base64) cost 1 credit. Standard tools (WHOIS, DNS, IP lookup) cost 5–10 credits. Heavier tools (subdomain enumeration, DMARC RUA aggregation, propagation across 30+ resolvers) cost 25–100 credits. Your monthly credit pool refreshes on your billing anniversary; overage billing is opt-in and priced at $0.50–$2 per 1,000 credits depending on tier.

04

Which languages have official code examples?

cURL, Python (requests), Node.js (fetch), Go (net/http), PHP (Guzzle), Ruby (Net::HTTP), Rust (reqwest), and Java (java.net.http). Every example hits the same endpoint with the same auth header — the API is designed to be language-agnostic and requires nothing more than an HTTPS client and a JSON parser.

05

What is the rate limit?

Rate limits are tier-based: Free tier at 60 req/min, Starter at 300 req/min, Pro at 600 req/min, Business at 1,200 req/min, and Enterprise negotiable. Rate limits are enforced per API key. When you hit the limit, the API returns HTTP 429 with a `Retry-After` header — the recommended pattern is exponential backoff starting at the header value.

06

Can I use the API from a browser or does it require a backend?

CORS is enabled for calls from browsers only when you use a scoped key configured with an allowed-origin. The default API key format is server-only — do not embed it in JavaScript shipped to end users. For client-side use, generate a scoped key in the dashboard, set its allowed origins, and treat it like a public token.

#developer-guide#domains#dns#domainscan
D
DomainScan Team
Writes about DNS infrastructure, email authentication, domain security, and the engineering behind automated domain intelligence.