# API docs

Everything on ziro.sh is static and public. No key and no account: fetch the file. Every JSON response uses the same envelope so a client can pin the schema version.

```json
{ "schema_version": 1, "generated_at": "2026-10-25T00:00:00.000Z", "data": [] }
```

## Endpoints

| Path                     | Returns                                     |
| ------------------------ | ------------------------------------------- |
| `/feed.json`             | Records from the last 30 days, newest first |
| `/records.json`          | Every published record                      |
| `/cve/{id}.json`         | One record by CVE or incident id            |
| `/week/{yyyy-ww}.json`   | One ISO week of records                     |
| `/schema/record.v1.json` | JSON Schema for a record                    |
| `/openapi.json`          | OpenAPI 3.1 description of these endpoints  |
| `/rss.xml`               | RSS 2.0, last 30 days                       |
| `/llms.txt`              | Index for language models                   |

## Quick start

```sh
curl -s https://ziro.sh/feed.json | jq '.data[] | {id, affects}'
```

Match `affects[].ranges` against your lockfile. Ranges use OSV and semver comparators, for example `>=8.4.0 <8.4.27`, and `fixed` lists the first safe version on each release line. Pick the smallest one above your installed version; jumping to the highest can mean a breaking major upgrade you don't need.

## Markdown for agents

Every page answers `Accept: text/markdown` with a Markdown version of itself, served with `Vary: Accept`. Record and week pages also answer `Accept: application/json` with their JSON twin.

```sh
curl -s -H 'Accept: text/markdown' https://ziro.sh/
```

## Record fields

| Field                          | Meaning                                                |
| ------------------------------ | ------------------------------------------------------ |
| `id`                           | CVE id, or a ziro incident id for events without one   |
| `kind`                         | `cve` or `incident`                                    |
| `severity`                     | `cvss`, `epss` (0 to 1) and `kev` (in CISA KEV)        |
| `affects`                      | Per package: `ecosystem`, `package`, `ranges`, `fixed` |
| `exploited_since`, `disclosed` | ISO dates, or null when unknown                        |
| `summary`                      | Two human-reviewed sentences                           |
| `sources`                      | At least two links the record is based on              |
| `review`                       | Who published it and when                              |

Empty beats guessed: a field the sources do not agree on is left null.

## MCP

An MCP server with `latest`, `get_cve` and `affects` tools is planned. It is not live yet; this page will list its URL when it is.

When it is, `affects` will return one match per affected package with:

| Field          | Meaning                                                                                    |
| -------------- | ------------------------------------------------------------------------------------------ |
| `fix`          | Smallest safe upgrade: the lowest fixed version above what you have installed              |
| `fix_breaking` | `true` when `fix` crosses a major version (or a minor on 0.x); `null` when there is no fix |
| `latest_fix`   | Highest fixed version the record lists. Often a bigger jump than you need                  |
| `uncertain`    | `true` when your version couldn't be compared; check it by hand                            |

Upgrade to `fix`, not `latest_fix`, unless you want the major bump anyway. Records list one fixed version per release line, so `fix` usually stays on your current major.

## Errors

Unknown paths return a real `404`. JSON paths, `/api/*` and requests that ask for JSON get [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem details with a stable `code`:

```json
{
  "type": "https://ziro.sh/docs#errors",
  "title": "Not found",
  "status": 404,
  "code": "not_found",
  "detail": "Nothing is published at /cve/CVE-1999-0001.json."
}
```

Markdown requests get a Markdown 404 and browsers get an HTML one. Anything other than `GET`, `HEAD` or `OPTIONS` returns `405` with `code: "method_not_allowed"`.

## Versioning

Every response carries `schema_version`. It changes only for a breaking change, such as a renamed or removed field; new optional fields do not bump it. A breaking change is announced on this page before it ships, and the previous version keeps being served alongside it for at least 30 days.
