---
title: API Catalog generator — publish a /.well-known/api-catalog linkset (RFC 9727)
description: "Free API Catalog generator: build a spec-valid /.well-known/api-catalog linkset (RFC 9727) that points agents at your API description documents, with entries verified against the manifests your site really publishes."
last_updated: 2026-07-17
canonical_url: https://agent-ready.dev/api-catalog-generator
---

# API Catalog generator

> Free API Catalog generator: build a spec-valid /.well-known/api-catalog linkset (RFC 9727) that points agents at your API description documents, with entries verified against the manifests your site really publishes.

## What it does

`/.well-known/api-catalog` is an RFC 9264 linkset, standardised by RFC 9727 (published 2024). Instead of an agent guessing where your API descriptions live — a root `/openapi.json` probe only catches one convention — the catalog is a single fetch that lists every API your site exposes and points at each one's machine-readable description via standard link relations. Add API entries (anchor, title, service-desc, service-doc), set the catalog URL, and optionally detect entries from your site's real manifests. Generation runs in your browser; the only network call is the optional probe of your site's own manifests.

## Why publish one

An agent landing on your homepage cannot find an API documented only on a subdomain. Without a catalog, the agent has to guess — probe `/openapi.json`, scrape your docs for links, or give up. The catalog is the one-fetch pointer: the agent reads `/.well-known/api-catalog` and knows about every API you publish, including cross-origin ones an OpenAPI-at-root probe would miss. This exact gap is why our scanner's C13 check exists — it fails a site that publishes no catalog, and it fails harder when a catalog exists but advertises nothing.

## What goes in the linkset

The catalog is a JSON object with a `linkset` array. The first member is the catalog index: its `anchor` is the catalog's own URL and its `item` list contains one entry per API. Each subsequent member describes a single API via three link relations:

- `anchor` — the API's URL (what the entry is about)
- `service-desc` — a link to the machine-readable description (OpenAPI, MCP card)
- `service-doc` — a link to human-readable documentation (optional)

```json
{
  "linkset": [
    {
      "anchor": "https://example.com/.well-known/api-catalog",
      "item": [
        { "href": "https://example.com/api", "title": "Example API" }
      ]
    },
    {
      "anchor": "https://example.com/api",
      "service-desc": [
        { "href": "https://example.com/openapi.json", "type": "application/openapi+json;version=3.1" }
      ],
      "service-doc": [
        { "href": "https://example.com/docs/api" }
      ]
    }
  ]
}
```

## The serve contract

Serve the file at `/.well-known/api-catalog` with Content-Type `application/linkset+json;profile="https://www.rfc-editor.org/info/rfc9727"`. RFC 9727 §4 requires the `linkset+json` media type; the profile parameter names the RFC the document conforms to. Serving it as plain `application/json` will still parse, but C13 flags it as a content-type degradation.

## Programmatic use

```bash
curl -X POST https://agent-ready.dev/api/v1/generate/api-catalog \
  -H "Content-Type: application/json" \
  -d '{
    "catalogUrl": "https://example.com/.well-known/api-catalog",
    "apis": [
      {
        "anchor": "https://example.com/api",
        "title": "Example API",
        "serviceDesc": "https://example.com/openapi.json",
        "serviceDescType": "application/openapi+json;version=3.1"
      }
    ],
    "url": "https://example.com"
  }'
```

Returns the generated linkset (`catalogJson`, `doc`), draft-level `warnings` (empty catalog, non-absolute URLs, missing service-desc), and — when `url` is given — the `detected` API surfaces that were merged into the catalog. The `contentType` field carries the RFC 9727 media type to serve the file as. No authentication required.

## Frequently asked questions

### What is /.well-known/api-catalog?

It is an RFC 9264 linkset, standardised by RFC 9727, served at /.well-known/api-catalog. Instead of an agent guessing where your API descriptions live (a root /openapi.json probe only catches one convention), the catalog is a single fetch that lists every API your site exposes and points at each one’s machine-readable description — OpenAPI, an MCP server card, or an A2A agent card — via standard link relations.

### How is the API catalog different from agents.json or an OpenAPI spec at the root?

An OpenAPI document describes one API’s operations. agents.json maps a REST API’s endpoints to agent-callable actions. The API catalog is broader: it is an index of every API the site publishes, cross-origin ones included, with each entry pointing at its own description document. An agent landing on your homepage fetches the catalog once and knows about every API — the OpenAPI at /api/v1/openapi.json, the MCP server at /.well-known/mcp.json, and the A2A endpoint at /.well-known/agent-card.json — without crawling or guessing.

### What link relations does RFC 9727 use?

The catalog is an RFC 9264 linkset. The first member is the catalog index: its anchor is the catalog’s own URL and its item list contains one entry per API (href + title). Each subsequent member describes a single API: its anchor is the API’s URL, and it carries service-desc (a link to the machine-readable description, e.g. an OpenAPI document) and optionally service-doc (a link to human-readable documentation). RFC 9727 requires these relations to contain real hyperlinks, not placeholders.

### What Content-Type should I serve the catalog as?

Serve it as application/linkset+json with the RFC 9727 profile parameter: application/linkset+json;profile="https://www.rfc-editor.org/info/rfc9727". RFC 9727 §4 requires the linkset+json media type; the profile parameter is the canonical, recommended form that names the profile the document conforms to. Serving it as plain application/json will still parse, but our scanner’s C13 check flags it as a content-type degradation.

### What happens if I publish an empty catalog?

An empty catalog is worse than not publishing one. An agent that fetches /.well-known/api-catalog and gets a 200 with a linkset that advertises no API hyperlinks has been told the catalog exists but contains nothing — it cannot fall back to guessing, because the site has explicitly declared it has no APIs to index. Our scanner’s C13 check fails a linkset that advertises no item, service-desc, or service-doc hyperlinks. The generator warns about this before you publish.

### Why does the generator ask for my site URL?

To seed the catalog with entries that verifiably exist. The generator probes your site’s real manifests (/openapi.json and friends, /.well-known/mcp.json, /.well-known/agent-card.json) and only offers entries it just fetched — it never invents an anchor or a service-desc URL. A catalog that points at a manifest your site doesn’t serve is a broken pointer that sends the agent back to scraping your docs; the detection step closes that loop.

### Where do I put the file?

Serve it at /.well-known/api-catalog with the Content-Type application/linkset+json;profile="https://www.rfc-editor.org/info/rfc9727". Optionally, advertise it from your homepage with a Link: rel="api-catalog" HTTP header so an agent can discover it from a HEAD request without parsing the HTML body. After publishing, run an agent-readability scan to confirm C13 grades the live file as a pass.

## The API catalog toolchain

- Generate: [API catalog generator](https://agent-ready.dev/api-catalog-generator)
- Scan: [Agent readability score](https://agent-ready.dev/agent-readability-score)

---

Generate your /.well-known/api-catalog on the web: <https://agent-ready.dev/api-catalog-generator>

## Sitemap

See the full [sitemap](https://agent-ready.dev/sitemap.md) for all pages on agent-ready.dev.
