A RESTful API for DNS lookups, domain intelligence, email authentication checks and cryptographic hashing — the same tools powering DigInterface, available programmatically.
✅
API Live. All endpoints documented below are active.
Generate an API key from your account dashboard to get started.
Base URL
https://www.diginterface.com/api/v2
All requests must be made over HTTPS. HTTP requests will be redirected to HTTPS. All request bodies must be JSON with Content-Type: application/json. All responses are JSON.
🔑 Authentication
All API requests require authentication using an API key passed in the Authorization header as a Bearer token. API keys can be generated from your account dashboard.
Authorization: Bearer di_a1b2c3d4e5f6g7h8i9j0k1l2
| Property | Detail |
| Format | di_ prefix followed by a 24-character alphanumeric string |
| Transmission | Always via Authorization: Bearer <key> header — never in query strings |
| Storage | Keys are stored hashed on the server — only the prefix (di_xxxx) is shown after creation |
| Scopes | Each key has scopes limiting which endpoints it can call. See Scopes below. |
| Expiry | Keys can be set to expire after 30, 60, or 90 days, or never expire. Expired keys return KEY_EXPIRED. |
| IP Allowlist | Optionally restrict a key to one or more IP addresses. Requests from other IPs return IP_NOT_ALLOWED. |
| Reset | Keys can be reset from the dashboard — generates a new secret while keeping all settings intact. Old key is immediately invalidated. |
| Revocation | Keys can be revoked instantly from the account dashboard |
Programmatic Login (JWT)
If you need a short-lived token for dashboard access or automation, you can exchange email and password for a 1-hour JWT using the /auth/token endpoint.
curl -X POST https://www.diginterface.com/auth/token \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com", "password": "yourpassword" }'
// Response
{
"status": "ok",
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600
}
⚠️
Treat your API key like a password. Do not commit it to source control or expose it in client-side code. If a key is compromised, reset or revoke it immediately from your dashboard.
🛡 Scopes
Every API key has one or more scopes that control which endpoints it can access. Scopes are assigned when a key is created and cannot be changed — create a new key if you need different scopes. A request made with a key that lacks the required scope returns a 403 INSUFFICIENT_SCOPE error.
| Scope | Endpoints covered |
dns |
POST /api/v2/dns/lookup POST /api/v2/dns/propagation |
domain |
POST /api/v2/whois POST /api/v2/ssl POST /api/v2/blacklist POST /api/v2/domain/age |
email |
POST /api/v2/spf/expand POST /api/v2/email/deliverability POST /api/v2/email/headers POST /api/v2/dmarc |
utils |
POST /api/v2/hash/text POST /api/v2/hash/url POST /api/v2/cidr POST /api/v2/qr/generate POST /api/v2/qr/decode |
account |
GET /api/v2/account/keys GET /api/v2/account/usage |
💡
For maximum security, create separate keys for each integration with only the scopes that integration needs. For example, a monitoring script that only checks SSL certificates only needs the domain scope.
⏱ Rate Limits
API requests are rate-limited per API key. The default limit is 100 requests per day. Account admins can increase this limit on a per-key basis for trusted integrations.
100
Default requests / day
Custom
Admin-configurable per key
Every response includes the following rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1745491200 # UTC epoch seconds when the window resets
When the rate limit is exceeded the API returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait.
❌ Error Codes
All errors follow a consistent format. HTTP status codes indicate the category of error; the code field provides a machine-readable identifier.
{
"status": "error",
"code": "INVALID_DOMAIN",
"message": "The value 'not-a-domain' is not a valid domain name",
"request_id": "req_7x8y9z"
}
| HTTP Status | Code | Description |
400 | INVALID_DOMAIN | The supplied domain name is malformed or empty |
400 | INVALID_IP | The supplied IP address is not a valid IPv4 or IPv6 address |
400 | INVALID_PARAMETER | A required parameter is missing or has an invalid value |
400 | INVALID_RECORD_TYPE | The requested DNS record type is not supported |
401 | MISSING_API_KEY | No Authorization header was provided |
401 | INVALID_API_KEY | The API key is invalid or has been revoked |
401 | KEY_EXPIRED | The API key has passed its expiry date — generate a new key from the dashboard |
403 | IP_NOT_ALLOWED | The request came from an IP address not on the key’s allowlist |
403 | INSUFFICIENT_SCOPE | The API key does not have the scope required for this endpoint |
429 | RATE_LIMIT_EXCEEDED | Daily request limit reached — resets at midnight UTC |
404 | DNS_NXDOMAIN | The domain does not exist (NXDOMAIN) |
404 | NO_SPF_RECORD | No SPF TXT record found for the domain |
422 | SPF_PERMERROR | SPF record has a permanent error (e.g. exceeds 10 DNS lookups) |
408 | DNS_TIMEOUT | DNS query timed out — try again |
502 | UPSTREAM_ERROR | Upstream DNS resolver or service returned an error |
500 | INTERNAL_ERROR | Unexpected server error — contact support if persistent |
🔖 Versioning
The API version is included in the URL path (/api/v2/). Breaking changes will result in a new version (v3). Non-breaking additions (new fields, new optional parameters) may be made to existing versions without notice. The api_version field in every response reflects the version that served the request.
🤖 MCP Endpoint
Every DigInterface tool is also available over the Model Context Protocol, the open standard that lets AI assistants like Claude call real tools instead of guessing from training data. Auth, scopes and rate limits are shared with the REST surface — one di_ API key works for both.
Endpoint URL
https://www.diginterface.com/mcp
Connecting from Claude
In Claude, go to Settings → Connectors → Add Custom Connector and enter:
| Name | DigInterface (or any label you prefer) |
| URL | https://www.diginterface.com/mcp |
| Auth | Leave blank for anonymous access at the shared rate limit, or paste a di_ API key as a bearer token for per-scope quotas. |
Available tools
All tools reuse the same scope taxonomy as the REST API — a key with the dns scope can call MCP tools that need dns, and so on. Some tools have a REST equivalent (documented below); others are MCP-only.
Anonymous vs authenticated
Anonymous requests (no Authorization header) are allowed for discovery and casual use — scope checks are bypassed and only the nginx per-IP limit applies. Authenticated requests (Authorization: Bearer di_...) are checked against the key's scope for every tools/call and count toward the key's daily quota exactly like REST.
Transport and rate limits
The endpoint speaks the MCP Streamable HTTP transport (JSON-RPC 2.0 over Server-Sent Events). Any MCP client implementing the 2025-11-25 or later specification should work.
Anonymous requests share a nginx-level limit of 30 per minute per IP. Authenticated requests draw from the same daily quota as REST (default 100/day per key, admin-configurable). Every tool invocation is logged to /account/usage so you can see MCP and REST traffic side by side.
💡
MCP is for when you want an assistant to run checks on your behalf. If you want to call these tools directly from code, use the REST endpoints documented below — same auth, same scopes.
DNS Lookup
Request Parameters
| Parameter | Type | Required | Description |
| domain |
string |
required |
The domain name to query (e.g. example.com) |
| record_types |
string[] |
optional |
Array of record types to query. Supported: A AAAA MX NS TXT SPF CNAME SOA PTR DMARC DKIM. Defaults to ["A","MX","TXT"] |
| resolver |
string |
optional |
Resolver to use: google (8.8.8.8), cloudflare (1.1.1.1), opendns, quad9. Defaults to google |
| dkim_selector |
string |
optional |
Required when DKIM is in record_types. The DKIM selector (e.g. google) |
curl -X POST https://www.diginterface.com/api/v2/dns/lookup \
-H "Authorization: Bearer di_a1b2c3d4e5f6g7h8i9j0k1l2" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com",
"record_types": ["MX", "TXT", "SPF"],
"resolver": "google"
}'
{
"status": "ok",
"api_version": "2",
"request_id": "req_7x8y9z",
"timestamp": "2026-04-24T10:00:00Z",
"data": {
"domain": "example.com",
"resolver": "google",
"records": {
"MX": ["10 mail1.example.com", "20 mail2.example.com"],
"TXT": ["v=spf1 ip4:203.0.113.0/24 include:_spf.google.com ~all"],
"SPF": ["v=spf1 ip4:203.0.113.0/24 include:_spf.google.com ~all"]
}
}
}
DNS Propagation
| Parameter | Type | Required | Description |
| domain | string | required | Domain name to check |
| record_type | string | optional | Record type to check. Defaults to A |
{
"status": "ok",
"data": {
"domain": "example.com",
"record_type": "A",
"propagated": true, // true if all resolvers agree
"resolvers": [
{ "name": "Google", "ip": "8.8.8.8", "result": ["93.184.216.34"], "status": "ok" },
{ "name": "Cloudflare", "ip": "1.1.1.1", "result": ["93.184.216.34"], "status": "ok" },
{ "name": "Quad9", "ip": "9.9.9.9", "result": [], "status": "timeout" }
]
}
}
WHOIS Lookup
| Parameter | Type | Required | Description |
| query | string | required | Domain name or IP address to look up |
{
"status": "ok",
"data": {
"query": "example.com",
"type": "domain",
"registrar": "IANA",
"created": "1995-08-14",
"expires": "2025-08-13",
"updated": "2023-08-14",
"status": ["clientDeleteProhibited", "clientTransferProhibited"],
"nameservers": ["a.iana-servers.net", "b.iana-servers.net"],
"raw": "Domain Name: EXAMPLE.COM\nRegistry Domain ID: ..."
}
}
SSL Certificate Check
| Parameter | Type | Required | Description |
| domain | string | required | Domain to inspect (port 443 assumed) |
| port | integer | optional | Port to connect to. Defaults to 443 |
{
"status": "ok",
"data": {
"domain": "diginterface.com",
"valid": true,
"subject": "CN=diginterface.com",
"issuer": "Let's Encrypt",
"expires": "2026-07-22T12:00:00Z",
"days_left": 89,
"sans": ["diginterface.com", "www.diginterface.com"],
"tls_version": "TLSv1.3",
"cipher": "TLS_AES_256_GCM_SHA384"
}
}
Blacklist Check
| Parameter | Type | Required | Description |
| target | string | required | IPv4 address or domain name to check |
{
"status": "ok",
"data": {
"target": "203.0.113.5",
"listed": true,
"list_count": 2,
"results": [
{ "list": "zen.spamhaus.org", "listed": true, "reason": "Policy Block List" },
{ "list": "bl.spamcop.net", "listed": false, "reason": "" },
{ "list": "dnsbl.sorbs.net", "listed": true, "reason": "SPAM source" }
]
}
}
SPF Record Expander
| Parameter | Type | Required | Description |
| domain | string | required | Domain whose SPF record should be expanded |
{
"status": "ok",
"data": {
"domain": "example.com",
"record": "v=spf1 include:_spf.google.com ~all",
"lookup_count": 4,
"ip4_count": 6,
"ip6_count": 3,
"flat_ips": [
{ "ip": "74.125.0.0/16", "type": "ip4", "qualifier": "pass", "source": "_spf.google.com" },
{ "ip": "209.85.128.0/17", "type": "ip4", "qualifier": "pass", "source": "_spf.google.com" }
]
}
}
Email Deliverability
| Parameter | Type | Required | Description |
| domain | string | required | Domain to check deliverability for |
| dkim_selector | string | optional | DKIM selector to check (e.g. google) |
{
"status": "ok",
"data": {
"domain": "example.com",
"score": 85,
"checks": [
{ "name": "SPF Record", "status": "pass", "message": "Valid SPF with ~all policy" },
{ "name": "DMARC Record", "status": "pass", "message": "p=reject policy" },
{ "name": "DKIM", "status": "warn", "message": "No selector provided" },
{ "name": "Blacklists", "status": "pass", "message": "Not listed on any DNSBL" },
{ "name": "PTR Record", "status": "pass", "message": "Reverse DNS matches forward" }
]
}
}
Hash Text
| Parameter | Type | Required | Description |
| text | string | required | The text to hash (UTF-8 encoded) |
| algorithms | string[] | optional | Array of algorithms. Supported: MD5 SHA-1 SHA-256 SHA-384 SHA-512. Defaults to all. |
{
"status": "ok",
"data": {
"input_length": 11,
"hashes": {
"MD5": "3e25960a79dbc69b674cd4ec67a72c62",
"SHA-1": "7b502c3a1f48c8609ae212cdfb639dee39673f5e",
"SHA-256":"a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"
}
}
}
Hash URL
| Parameter | Type | Required | Description |
| url | string | required | Public HTTPS URL of the file to fetch and hash. Maximum 512 MB. |
| algorithms | string[] | optional | Hash algorithms to compute. Defaults to ["MD5","SHA-256"] |
{
"status": "ok",
"data": {
"url": "https://example.com/file.zip",
"filename": "file.zip",
"size": 1048576,
"size_fmt": "1.0 MB",
"hashes": {
"MD5": "d41d8cd98f00b204e9800998ecf8427e",
"SHA-256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
}
}
Domain Age
| Parameter | Type | Required | Description |
| domain | string | required | Domain to look up (e.g. example.com) |
{
"status": "ok",
"data": {
"domain": "example.com",
"created": "1995-08-14T04:00:00+00:00",
"created_human": "14 August 1995",
"expires": "2026-08-13T04:00:00+00:00",
"expires_human": "13 August 2026",
"registrar": "IANA",
"status": "clientTransferProhibited",
"age": "30 years, 11 months, 14 days",
"age_days": 11302,
"days_until_expiry": 15
}
}
DMARC Analyser
| Parameter | Type | Required | Description |
| domain | string | required | Domain to analyse. Do NOT prepend _dmarc. — the tool adds it. |
{
"status": "ok",
"data": {
"domain": "example.com",
"record": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; pct=100",
"tags": {
"v": "DMARC1",
"p": "reject",
"rua": "mailto:dmarc@example.com",
"pct": "100"
},
"summary": "DMARC policy=reject, aggregate reports enabled",
"warnings": []
}
}
💡
A 404 NO_DMARC_RECORD response means _dmarc.<domain> either does not exist or has no v=DMARC1 record.
CIDR / Subnet Info
| Parameter | Type | Required | Description |
| cidr | string | required | IPv4 or IPv6 CIDR (e.g. 10.0.0.0/8, 2001:db8::/32). A bare address is treated as /32 (v4) or /128 (v6). |
{
"status": "ok",
"data": {
"cidr": "10.0.0.0/24",
"version": 4,
"network_address": "10.0.0.0",
"broadcast_address": "10.0.0.255",
"netmask": "255.255.255.0",
"hostmask": "0.0.0.255",
"prefix_length": 24,
"num_addresses": 256,
"usable_hosts": 254,
"first_usable": "10.0.0.1",
"last_usable": "10.0.0.254",
"is_private": true,
"is_global": false,
"is_multicast": false,
"is_reserved": false,
"is_loopback": false
}
}
QR Code Generator
| Parameter | Type | Required | Description |
| data | string | required | Text or URL to encode. Maximum ~2900 characters. |
| format | string | optional | png (default) returns a base64-encoded image; unicode returns block-character art plus the raw module matrix. |
| ec_level | string | optional | Error-correction level: L (7%), M (15%, default), Q (25%), H (30%). Higher tolerates more damage but produces a denser code. |
| box_size | integer | optional | PNG only — pixels per QR module. Clamped to [5, 20]. Defaults to 10. |
| border | integer | optional | Quiet-zone width in modules. Defaults to 4 for PNG, 2 for unicode. |
curl -X POST https://www.diginterface.com/api/v2/qr/generate \
-H "Authorization: Bearer di_a1b2c3d4e5f6g7h8i9j0k1l2" \
-H "Content-Type: application/json" \
-d '{
"data": "https://www.diginterface.com",
"format": "png",
"ec_level": "M",
"box_size": 10
}'
{
"status": "ok",
"data": {
"png_base64": "iVBORw0KGgoAAAANSUhEUgAAAOwAAADsCAYAAA...",
"content_type": "image/png"
}
}
{
"status": "ok",
"data": {
"unicode_art": "███████████████████...\n██ ▄▄▄▄▄ █▄█▀██▄█▀▀...", // half-block-character grid
"line_count": 15,
"matrix": [ // raw 0/1 module grid, includes quiet zone
[0, 0, 0, 0, ...],
[0, 1, 1, 1, ...]
]
}
}
💡
The matrix returned with format=unicode is the raw QR module grid — 1 = dark module, 0 = light — including the quiet-zone border. Callers can render it into their own visual form (e.g. a colored-<td> HTML table for pasting into Word/Outlook).
QR Code Decoder
Accepts either multipart/form-data with an image file field, or application/json with an image_base64 string. Multiple codes in one image are all returned. 5 MB image size cap. Accepts PNG, JPEG, GIF, WebP, and BMP.
| Parameter | Type | Required | Description |
| image | file | multipart | Image file, submitted as a multipart upload. Preferred for CLI usage. |
| image_base64 | string | json | Raw image bytes, base64-encoded. Preferred for JSON-only callers. Standard or URL-safe alphabet. |
curl -X POST https://www.diginterface.com/api/v2/qr/decode \
-H "Authorization: Bearer di_a1b2c3d4e5f6g7h8i9j0k1l2" \
-F "image=@qr-code.png"
curl -X POST https://www.diginterface.com/api/v2/qr/decode \
-H "Authorization: Bearer di_a1b2c3d4e5f6g7h8i9j0k1l2" \
-H "Content-Type: application/json" \
-d '{ "image_base64": "iVBORw0KGgoAAAA..." }'
{
"status": "ok",
"data": {
"results": [
{
"data": "https://www.diginterface.com",
"type": "QRCODE",
"rect": { "left": 40, "top": 40, "width": 290, "height": 290 }
}
]
}
}
💡
An empty results list means the image decoded successfully but no QR / barcode was found in it — not an error. Barcodes (EAN, Code 128, etc.) are also detected and returned with the appropriate type value.
List API Keys
{
"status": "ok",
"data": {
"keys": [
{
"prefix": "di_a1b2",
"name": "Production key",
"scopes": "dns,domain,email,utils,account",
"rate_limit": 100,
"expires_at": "2026-07-26T00:00:00Z", // null if never expires
"created_at": "2026-04-27T10:00:00Z",
"last_used": "2026-04-27T14:32:00Z", // null if never used
"is_active": true
}
]
}
}
API Usage
{
"status": "ok",
"data": {
"key_prefix": "di_a1b2",
"requests_today": 27,
"requests_limit": 100,
"requests_remaining":73,
"reset_at": "2026-04-25T00:00:00Z"
}
}