# HTTP API

> One domain with no account through POST /api/lookup, and the SVG badge at GET /api/badge/{domain}.

Two endpoints, both usable with no account.

## POST /api/lookup

One domain, no account, 10 requests a minute per IP.

```bash
curl -s https://domduck.com/api/lookup \
  -H "content-type: application/json" \
  -d '{"domain":"stripe.com"}'
```

```json
{
  "domain": "stripe.com",
  "domainRating": 95,
  "fetchedAt": "2026-08-03T06:59:19.000Z",
  "rank": 236,
  "backfilled": 0,
  "registration": {
    "registeredAt": "1995-09-12T04:00:00Z",
    "ageDays": 11283,
    "registrar": "SafeNames Ltd."
  },
  "tls": { "valid": true, "issuer": "DigiCert Inc", "daysRemaining": 101 },
  "series": {
    "dr": [{ "t": "2026-08-03", "v": 95 }],
    "rank": [{ "t": "2026-07-28", "v": 236 }]
  }
}
```

**This is the one endpoint that may go upstream.** It answers from the store
when the stored Domain Rating is under twelve hours old, and fetches only on a
miss. Everything else Domduck exposes reads the store and nothing else.

Deliberately one domain per request. A bulk lookup is an account feature.

| Field | Notes |
|---|---|
| `domainRating` | Ahrefs Domain Rating, 0-100, higher is better. |
| `rank` | Tranco rank inside the top 1M. **Lower is better.** `null` outside it. |
| `backfilled` | Rank points written on this call. `0` on a cached answer, because nothing was written. |
| `registration`, `tls` | Best effort. `null` when a slow registry or a failed handshake would otherwise have cost you the rating. |
| `series` | Up to 90 days, oldest first, one point per reading. `v` may be `null`. |

Failures: `400` for something that is not a domain, `429` when you or the
upstream are rate limited, `502` when no rating could be read.

## GET /api/badge/{domain}

An SVG badge for embedding on another site.

```html
<a href="https://domduck.com/domain/stripe.com?utm_source=example.com" target="_blank">
  <img src="https://domduck.com/api/badge/stripe.com"
       alt="Monitor your Domain Rating with Domduck"
       width="138" height="24">
</a>
```

The badge **never talks to Ahrefs.** It reads Domduck's store, so a domain
nobody has looked up renders a dash rather than triggering a fetch.

Height is always 24. Width is computed from the text: 135 for a one-digit
rating, 138 for two digits, 147 for 100, 135 for an unknown domain. Two digits
is almost everything, which is why the snippet says 138. An `img` whose
attributes disagree with the SVG scales rather than crops, so if you generate
the snippet, generate the width too, or omit both attributes and accept the
layout shift.

## What is not here

There is no bulk endpoint and no domain list endpoint, on purpose. An open
endpoint that returns a rating for any name you hand it is a free dataset, and
the Ahrefs licence Domduck reads Domain Rating under forbids compiling one.
Every public surface reads what a real person already asked for.
