Anubis-DB

September 6, 2026 ยท View on GitHub

Sister project to Anubis

About

This project came about due to a lack of free and open APIs for subdomain enumeration.

Usage

There is only one endpoint - https://anubisdb.com/anubis/subdomains/:domain, where :domain is the domain.

MethodEndpointParameters
GEThttps://anubisdb.com/anubis/subdomains/ + domaindomain: Valid domain (e.g. google.com, reddit.com, etc)
POSThttps://anubisdb.com/anubis/subdomains/ + domainsubdomains: Array of submitted subdomains

GET returns the full list of known subdomains for the domain. POST stores valid submitted subdomains and returns counts only; it does not return the full stored subdomain list. Use GET after POST if you need the current full list.

The API supports cross-origin browser requests, including JSON POST preflights.

A sample AJAX GET request looks like:

fetch("https://anubisdb.com/subdomains/reddit.com", {
  method: "GET",
  headers: {
    "Content-Type": "application/json",
  },
})
  .then((response) => response.json())
  .then((data) => {
    // Handle data here
    console.log(data);
  })
  .catch((error) => {
    // Handle error here
    console.error("Error:", error);
  });

A sample AJAX POST request looks like:

fetch("https://anubisdb.com/subdomains/reddit.com", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    subdomains: ["www.reddit.com", "old.reddit.com"],
  }),
})
  .then((response) => response.json())
  .then((data) => {
    // {
    //   domain: "reddit.com",
    //   created: false,
    //   acceptedSubdomainCount: 2,
    //   insertedSubdomainCount: 1
    // }
    console.log(data);
  })
  .catch((error) => {
    console.error("Error:", error);
  });

Status Codes

StatusEndpoint
200Success
201New domain created
400Malformed request body
403Invalid domain or subdomains
413Submission exceeds input or domain storage limits
429Rate limit exceeded
500Server error saving or retrieving new subdomains

Limits

You're limited to 60 requests per 10 seconds per source IP. This is enforced at Cloudflare's edge before requests reach the Worker.

IPs or prefixes found trying to bypass the rate limit by rotating addresses or otherwise evading enforcement may be challenged or blocked.

There is also a 10,000 unique subdomain limit per domain and a 2,000,000-byte limit for its stored JSON array. Submissions that exceed either limit return 413 without partially adding subdomains.

POST bodies are limited to 3,000,000 bytes, including streamed requests. Each request may contain up to 10,000 array items and 10,000 values after splitting commas, line breaks, or HTML breaks. Empty, invalid, and duplicate values count toward these input limits. Each value may contain at most 2,048 characters; URL-encoded requests may contain at most 100 form fields. Split larger submissions into separate requests. Rejected submissions do not partially add data.

Additions are merged atomically in D1, so concurrent submissions preserve each other's values. For domains at capacity, an indexed precheck handles duplicate or rejected submissions without repeatedly scanning JSON values as billable rows. Smaller domains incur one extra indexed read; successful changes still use the atomic merge. Empty or duplicate-only POSTs retain cached GET results. Concurrent GET cache misses share a read within each Worker isolate; the edge cache retains the existing five-minute lifetime. HTTP/HTTPS and the apex/www production hosts share the same cache entries and invalidation.

Worker CPU time is capped at 500 ms per invocation. A production analytics review on September 6, 2026 covered approximately 90 days and 27.2 million requests: successful requests reached 139 ms of CPU, with peaks above 100 ms on four days. The 500 ms limit leaves headroom for rare large submissions and variation beyond those sampled observations. Network and D1 wait time do not count toward Worker CPU; billing uses actual CPU consumed, not the configured ceiling.

The workers.dev route and preview URLs are explicitly disabled so traffic uses the configured production hosts. Routine invocation logs and tracing are disabled; server errors are still logged. These controls bound work per request, but total request volume remains billable and is not a monthly spending cap.

Cloudflare Workers and D1

This service runs as a Cloudflare Worker backed by the anubis-db D1 database.

Useful commands:

pnpm install --frozen-lockfile
pnpm dev
pnpm db:migrate:local
pnpm db:migrate:remote
pnpm migrate:postgres
pnpm run deploy

Use Node.js 22.12 or newer and the pnpm version pinned in package.json. Run pnpm lint for Oxlint, pnpm format to format with Oxfmt, and pnpm format:check to check formatting. Validate changes with pnpm typecheck and pnpm test.

pnpm migrate:postgres reads the source PostgreSQL URL from DB_URL or SOURCE_DB_URL, exports a consistent read-only snapshot into a unique .d1-import/run-<unique>/ directory, and applies the SQL chunks to the remote D1 database with Wrangler. D1_IMPORT_DIR overrides the parent directory; existing files and other export runs are preserved. Keep CLOUDFLARE_API_TOKEN in the shell environment when running remote D1 or deploy commands.

Contributing

The most straightforward way of contributing is just to use Anubis and have it sends its results to AnubisDB.

Contributions to AnubisDB are always appreciated, as well. Currently parsing and over-use protections are lacking. Take a look at the issues and see if there is anything that you'd like to contribute to.