The dug API
Every command is a GET. There’s no key, no signup and no request body to build, and every response publishes the quota. The same URL answers in three representations, and the browser app at / is one of them, not a separate product.
$ curl https://dug.sh/tls/github.com
$ curl https://dug.sh/dig/example.com/MX
$ curl -H 'Accept: application/json' https://dug.sh/mail/github.com
The query form is equivalent and is what the browser app uses: /api/tls?command=TLS&target=github.com
- text/plain
- the default for curl and other terminal clients
- application/json
- Accept: application/json, or ?format=json
- text/markdown
- Accept: text/markdown, on the pages
- text/html
- the browser app; a command url opened in a browser lands there with the command run
- Vary
- Accept, User-Agent, so negotiation is cache safe
- Cache-Control
- derived from the answer’s own TTL, floored at 30s
None. Reads are open and there’s no key to obtain, so there’s nothing here to sandbox. The guard validates every destination before connect, which is what makes open reads safe. The quota below applies per address, since there’s no key.
An upstream that fails mid-answer is 200: the failure is named in degraded and the rest of the answer is real. Arguments that are wrong are 400, because nothing was looked up. Only a 4xx carries error, so its presence and the status always agree.
- error.code
- missing_argument, invalid_argument
- error.message
- the refusal in one sentence
- error.hint
- what a corrected call looks like
Branch on the code, never on the message. The text representation carries the same code on a line reading "error <code>".
- RateLimit-Limit
- 60 requests per window
- RateLimit-Remaining
- what is left in this window
- RateLimit-Reset
- seconds until it resets
- RateLimit-Policy
- "fixed";q=60;w=60, per RFC 9331
- over the quota
- 429, error.code rate_limited, Retry-After
Every response carries these, including a 200, so a caller can pace itself instead of discovering the ceiling by hitting it. The count lives in the memory of one proxy instance, and a serverless deployment runs more than one, so a client spread across instances gets more than 60. It’s a real backstop and a truthful number to pace against. It isn’t a security control.
The paths are unversioned and additive. New commands, blocks and fields may appear at any time, so parse defensively and ignore what you don’t recognise. A change that would break an existing caller ships under a /v2/ prefix instead of changing these.
- X-API-Version
- on every response, naming the contract it ran under
- Deprecation
- an http-date, the day it became deprecated
- Sunset
- an http-date, the day it stops answering
- notice
- at least 180 days between the two dates
Nothing is deprecated today, and the absence of a Deprecation header is how you can tell. The full timeline is at /deprecation.
Endpoints
- GET /dig/{target}every record type, or a single one
- GET /prop/{target}agreement across the fixed resolver list
- GET /ttl/{target}remaining lifetime per record
- GET /ns/{target}root to tld to authoritative walk
- GET /dnssec/{target}chain of trust, ds and dnskey
- GET /rdap/{target}registration data with status codes decoded
- GET /watch/{target}domain and certificate expiry, computed now
- GET /tls/{target}chain, validity spans, protocols
- GET /http/{target}headers, redirect chain, security headers
- GET /trace/{target}dns, tcp, tls and ttfb timing
- GET /mail/{target}mx, spf, dkim, dmarc and alignment policy
- GET /spf/{target}include tree, against the ten lookup limit
- GET /ip/{target}reverse dns, asn, prefix, neighbours
- GET /asn/{target}prefixes and address space
- GET /net/{target}address space grid, a /24 or smaller
- GET /methe address this request came from
- GET /ping/{target}icmp echo, round trip time and packet loss
- GET /route/{target}the hops between here and there, with reverse dns
- GET /ports/{target}which tcp ports are open, closed or filtered
- GET /vs/{target}two domains side by side
- GET /srcresolver list, cache ceilings, upstream health
- GET /seo/{target}what a crawler reads: title, canonical, robots, structured data
- GET /aeo/{target}what an answer engine reads: llms.txt, markdown, content without js
- GET /og/{target}the share card, with the image fetched and measured
- GET /webmcp/{target}tools for an agent in the page, and the mcp surface for one that isn’t
- /llms.txtthe grammar, the limits, when to use this
- /openapi.jsonopenapi 3.1, one operation per command
- /.well-known/api-catalogrfc 9727 linkset
- /.well-known/ai-catalog.jsonai catalog, typed by protocol
- /.well-known/mcp/server-card.jsonmcp server card, every tool without connecting
- /server.jsonmcp server manifest
- /mcpmcp over streamable http, post only
- /deprecationhow a route is retired
- /contactreport a wrong answer