Duvlify
GitHubGet started
Building the siteAPI reference pages
Building the site

API reference pages

Point the build at an OpenAPI document, and endpoint pages render their parameters, schemas, response tabs, and request samples from it.

An endpoint page carries only the identity of one operation. The build resolves everything it renders from your OpenAPI document at build time: parameters, request bodies, response shapes, the response tabs, and the generated client snippets. The spec stays the single source of truth, and no MDX restates a field name.

Point the build at a spec

src/openapi.config.ts exports one object: an OpenAPI 3.1 document. Write it inline, or import it from a JSON file the build can read.

src/openapi.config.ts
export const openapiSpec = {
  openapi: '3.1.0',
  info: { title: 'Example API', version: '2026-08-01', description: '…' },
  servers: [{ url: 'https://api.example.com/v1', description: 'Production' }],
  security: [{ bearerAuth: [] }],
  tags: [{ name: 'Flags', description: 'Flag definitions and their variations.' }],
  paths: {
    '/flags': {
      get: {
        operationId: 'listFlags',
        summary: 'List flags',
        tags: ['Flags'],
        parameters: [/* … */],
        responses: {/* … */},
      },
    },
  },
} as const;

An empty paths value is the off switch. With no operations, the build does not emit the /openapi.json route. It leaves the service-desc link out of the document head. The Optional section of llms.txt says nothing about a spec, and the API catalog leaves the API out.

The last point is the reason this matters. A person who opens an empty spec closes it and moves on. An agent may instead read the empty spec as evidence that your API has no endpoints, and answer a question about your product accordingly.

Write the endpoint page

content/api/flags/list.mdx
---
title: List flags
description: Returns flags in the given environment, newest first, with cursors that stay valid as flags are created.
pageType: api-endpoint
apiMethod: GET
apiPath: /flags
apiOperationId: listFlags
apiTag: Flags
---

apiMethod and apiPath must match an operation in the configured spec. apiOperationId and apiTag are optional overrides. The body of the page is ordinary MDX. Use it for the things a spec cannot express: why an endpoint exists, when to use it over another, and what a caller usually gets wrong.

Add the operation to the spec

Add parameters, request body, responses, and schemas. This is where field names live, and the only place they live.

Create the page with the frontmatter above

Method and path are the join key. A mismatch fails the build instead of rendering an empty reference.

List the page in a navigation group

Exactly like any other page — see Authoring.

Name the tab in seo.apiReferenceTabs

src/docs.config.ts
apiReferenceTabs: ['api'],

The build then types those pages as schema.org APIReference rather than TechArticle. This is named explicitly rather than inferred from the contents, because a showcase that illustrates an endpoint is not an API reference. Structured data that overstates what a page is earns a manual action rather than a rich result.

The layout you get

An endpoint page uses a wider three-track frame: navigation, prose, and a sticky right rail that holds the request and response examples. Below 1280px the rail column is hidden, and those components return to the article.

A prose page can opt into the same shape with rightRail: custom in frontmatter. Both layouts put prose in the middle with examples alongside, so they share one set of widths instead of each keeping its own.

Write spec descriptions in Markdown

OpenAPI defines description as CommonMark, and the build renders it as such. A `field_name` in a schema description becomes a code chip, exactly as it would in a page.

TypeScript
{
  name: 'starting_after',
  in: 'query',
  description: 'A flag key. Returns the page immediately after it. See `limit` for page size.',
  schema: { type: 'string', example: 'checkout-v2' },
}

This is the one place where prose reaches a page without going through MDX. src/lib/spec-markdown.ts runs those strings through Astro’s own Markdown processor. A spec fetched from elsewhere at build time would need sanitising there first.

The spec is published too

When you configure a spec, the build serves it whole at /openapi.json, with the application/openapi+json media type that agents look for.

The endpoint pages render the spec as prose, tables, and code samples. That shape suits a person but not a tool writing code against the API. Such a tool needs the exact parameter names, the enum members, and the response schema, not a description of them. Publishing the source document costs one route and removes the entire class of “the docs said the field was optional” mistakes.

Writing parameter fields by hand

Write the fields yourself for an API this framework does not drive, or for a configuration object rather than an endpoint.

webhookstring

Where report_issue delivers. Hidden from the tool list until it is set.

rateLimitobjectrequired

Requests per minute per IP, per tool family.

See Components for the full set.

Use these docs with your AI tools

An AI agent can read this documentation directly. You do not need an account or an API key. Everything here is public and read-only.

Query these docs via MCP

Recommended

Add this server to Claude, Claude Code, Cursor, Mistral, or any tool that supports MCP. Your agent can then search Duvlify documentation and read it in full, instead of answering from memory.

https://duvlify.dev/mcp
  • searchFind the passages that answer a question.
  • fetchRead one page in full, as Markdown.
  • list_pagesSee every page in this documentation.

Query these docs over HTTP

The same tools also work as plain web requests. Use this for scripts, or for any tool that does not support MCP. There is one endpoint per tool. Arguments go in the query string, and the answer comes back as JSON.

https://duvlify.dev/api/docs/search?query=custom+domain

Read the OpenAPI description. It is built from the same definitions as the tools, so it always matches what the endpoints do.

Read these docs as Markdown

Add .md to any page URL to get its Markdown source. You can also send the headerAccept: text/markdown to the page URL itself.

To read the whole documentation in one file, open llms-full.txt. For a short index of every page, open llms.txt.