# OpenAPI Spec

> How to create an OpenAPI specification for AI agents: the missing file, version, info, paths, and servers.

Diese Prüfung trägt 4 % des Scores.

*Diese Leitfäden zur Behebung sind in englischer Sprache verfasst.*

<a id="not-found"></a>

## openapi.json not found

Create `/.well-known/openapi.json` with your API specification. Even if your site doesn't have a traditional REST API, you can document any data endpoints:

```
{
  "openapi": "3.1.0",
  "info": {
    "title": "Your Site API",
    "description": "API providing structured data for Your Site.",
    "version": "1.0.0",
    "contact": {
      "name": "Your Name",
      "url": "https://your-site.com",
      "email": "email@your-site.com"
    }
  },
  "servers": [
    {
      "url": "https://api.your-site.com",
      "description": "Production API"
    }
  ],
  "paths": {
    "/data": {
      "get": {
        "operationId": "getData",
        "summary": "Get all data",
        "description": "Returns structured data.",
        "responses": {
          "200": {
            "description": "Successful response"
          }
        }
      }
    }
  }
}
```

> **Quick fix with ax-init**
>
> Run
>
> npx ax-init
>
>  and select "OpenAPI Spec" to generate a starter openapi.json based on your site.

---

<a id="wrong-content-type"></a>

## Wrong Content-Type

Serve `/.well-known/openapi.json` with `Content-Type: application/json`. If you publish a YAML variant alongside, use `application/yaml` for the `.yaml` URL, but the JSON path should always return JSON MIME.

---

<a id="invalid-json"></a>

## Invalid JSON

Your openapi.json has invalid JSON syntax. Validate it with a JSON linter or the [Swagger Editor](https://editor.swagger.io/).

---

<a id="upgrade-swagger"></a>

## Upgrade from Swagger 2.x

Your spec uses Swagger 2.x (`"swagger": "2.0"`). AI agents work better with OpenAPI 3.x which has improved schema support, better parameter handling, and is the current standard.

Use the [Swagger Editor](https://editor.swagger.io/) to convert your 2.x spec to 3.x, or change the root field from `"swagger"` to `"openapi"` and update the structure accordingly.

---

<a id="no-version"></a>

## No version field

Add `"openapi": "3.1.0"` to the root of your spec to declare the OpenAPI version.

---

<a id="missing-title"></a>

## Missing info.title

Add an `info` object with a `title` field. This is the name AI agents will use to identify your API.

```
"info": {
  "title": "Your API Name",
  "version": "1.0.0"
}
```

---

<a id="missing-description"></a>

## Missing info.description

Add a `description` field inside `info` explaining what your API provides and how AI agents can use it. Be specific about data types and use cases.

---

<a id="no-paths"></a>

## No paths documented

Add a `paths` object documenting your API endpoints. Each path should include the HTTP method, operation ID, summary, and response schema. Even one well-documented endpoint is better than none.

---

<a id="no-servers"></a>

## No servers defined

Add a `servers` array with your API base URL so AI agents know where to send requests:

```
"servers": [
  {
    "url": "https://api.your-site.com",
    "description": "Production API"
  }
]
```

---

<a id="undiscoverable"></a>

## A description nothing points at

The check found your OpenAPI file by trying known filenames, which is what an agent has to do too. Guessing works until it does not, and it costs a request per guess.

Advertise it once and the guessing stops:

```
Link: </openapi.json>; rel="service-desc"
```

Or in the document, which survives a CDN that strips headers:

```
<link rel="service-desc" href="/openapi.json">
<link rel="service-doc" href="/docs">
```

---

<a id="catalog-content-type"></a>

## The catalog is served as the wrong type

An RFC 9727 catalog is a JSON linkset and answers with `application/linkset+json`. Served as plain JSON, a client dispatching on content type will not recognise it.

---

<a id="catalog-invalid"></a>

## The catalog is not a linkset

The document parses and is not shaped like RFC 9264 expects: a `linkset` array of entries, each with an `anchor` and its links. An ad-hoc list of URLs is a different thing wearing the same filename.

```
GET /.well-known/api-catalog
Content-Type: application/linkset+json

{
  "linkset": [
    {
      "anchor": "https://api.example.com",
      "service-desc": [{ "href": "https://example.com/openapi.json" }],
      "service-doc":  [{ "href": "https://example.com/docs" }]
    }
  ]
}
```

---

<a id="catalog-empty"></a>

## A catalog entry describing nothing

An entry needs an anchor and at least one `service-desc` or `service-doc` link. Without either it names an API and says nothing about it.

---

<a id="catalog-anchor"></a>

## An entry with no anchor

The anchor is the URI of the API being described. It is what makes a catalog listing several APIs unambiguous, so an entry without one cannot be attached to anything.

---

<a id="catalog-service-doc"></a>

## A machine description with no human one

Pair every `service-desc` with a `service-doc`. The first is what an agent parses; the second is what it shows a person who asks where the answer came from, and an agent that cannot cite your documentation tends to describe your API in its own words instead.

---

<a id="swagger-2"></a>

## Swagger 2.0

The document is Swagger 2.0 rather than OpenAPI 3. Tooling support is fading, and 3.1 aligns with JSON Schema, which is what a model uses to build a call. Converting is mostly mechanical and most generators do it.

---

<a id="no-title"></a>

## No info.title

The title is what an agent shows when choosing between several tools. An untitled API is one it cannot describe to the person who asked.

---

<a id="no-description"></a>

## No info.description

This is the text an agent reads to decide whether your API is the one it needs. A list of endpoints tells it what it can call; the description tells it why it would.

---

<a id="operation-ids"></a>

## Operations without operationId

Without an `operationId`, tooling generates a name from the method and path, and that name changes whenever the path does. An agent that stored a reference to your endpoint finds it gone after a refactor that changed nothing it depended on.

---

Markdown-Darstellung von https://axrush.com/guides/api-discovery
