How to
How to document an API with an AI agent
Point the agent at the routes. It writes one endpoint block per route — method, path, params, body, responses, an example pair — and a sequence of how a client uses them. chiltepin check verifies the structure; the renderer draws the reference.
1. Give the agent the request
Install the skill once — npx skills add jdiejim/chiltepin -g — then say what the reader needs, in plain words. Do not name a block type; picking it is the skill's job.
Read src/api/routes/orders/ and document the orders REST API in docs/api/orders.md: every endpoint with params, body, responses and an example, plus how a client creates an order and polls it. Run chiltepin check.
Naming the directory makes the agent read code instead of guessing paths. Asking for “how a client creates an order and polls it” gets the sequence diagram that a list of endpoints never explains on its own.
2. What the agent picks, and why
The skill reads the request as the reader's question and answers it with two to five blocks, each a different lens. For this request it picks:
endpoint— one per route — method, path, auth, params by location, body fields with types, responses with meaning, and a request/response examplesequence— the client’s path through the endpoints — create, poll, receive the webhook — so the order of calls is documented, not impliedtable— the error contract — every error code, its HTTP status and what the client should do, in one place
Before writing each one it runs chiltepin block <type>, which prints the fields, enums and terse forms from the schema. It writes YAML; it never places a shape.
The block it wrote
The first endpoint block the agent wrote for the orders API in the gallery, unedited: POST /v1/orders with an idempotency header, five body fields, five responses and an example pair.
```endpoint
method: POST
path: /v1/orders
description: "Submit line items and a shipping address. The order starts in PAYMENT_PENDING and the gateway captures the payment asynchronously."
auth: Bearer api_key
params:
- { name: Idempotency-Key, in: header, type: string, required: true, desc: "Unique per attempt. Reuse it on retry to get the original response." }
body:
- { name: items, type: "LineItem[]", required: true, desc: "One or more of { sku, qty }. qty is 1..99." }
- { name: shipping_address, type: Address, required: true, desc: "name, line1, line2, city, postal_code, country (ISO 3166-1 alpha-2)." }
- { name: currency, type: string, required: true, desc: "ISO 4217 code, for example USD." }
- { name: payment_method_id, type: string, required: true, desc: "Token from the hosted payment gateway, prefix pm_." }
- { name: customer_reference, type: string, desc: "Free text the client can search by later, max 64 chars." }
responses:
- { status: 201, desc: "Order created; status is PAYMENT_PENDING." }
- { status: 400, desc: "Malformed JSON or a field fails validation." }
- { status: 401, desc: "Missing or invalid API key." }
- { status: 409, desc: "Idempotency-Key reused with a different body." }
- { status: 422, desc: "A sku is unknown or has no stock (code sku_unknown or out_of_stock)." }
request: |
{
"items": [{ "sku": "MUG-BLUE-12OZ", "qty": 2 }],
"shipping_address": {
"name": "Ada Lovelace", "line1": "12 Analytical St",
"city": "London", "postal_code": "N1 9GU", "country": "GB"
},
"currency": "GBP",
"payment_method_id": "pm_9f3k2",
"customer_reference": "web-checkout-77120"
}
response: |
{
"id": "ord_01J8Q2ZK4M",
"status": "PAYMENT_PENDING",
"currency": "GBP",
"total_cents": 2400,
"items": [{ "sku": "MUG-BLUE-12OZ", "qty": 2, "unit_price_cents": 1200 }],
"created_at": "2026-09-13T10:02:11Z",
"updated_at": "2026-09-13T10:02:11Z"
}
```3. Check it
The agent runs npx -y chiltepin check docs/<file>.md --json. Every diagnostic has a stable code, the file and line, and a hint. One it might see on a first draft:
E_SCHEMA docs/api/orders.md:18 endpoint: unknown field 'parameters'
hint: Valid fields: method, path, title, description, auth, params, body, responses, request, response.It fixes what the hint says and re-runs the check. A change is not done until the check passes — and in CI the same command fails the build, so a document cannot drift silently.
4. Render it
npx chiltepin html docs/api/orders.md -p renders the reference with an anchor per endpoint. chiltepin build publishes it with the rest of the docs. If a spec exists, chiltepin sync openapi openapi.yaml --out docs/api/orders.md --check in CI fails when the doc and the spec disagree.
See it done
The agent-written document for this request is in the gallery: Orders REST API, shown exactly as generated from “Document the public REST API for the orders service.”. Related: software design documents, the API reference, and the blocks endpoint, sequence, eventcontract.
Frequently asked questions
- What should API documentation contain?
- Per endpoint: method, path, what it does, authentication, parameters by location, the request body, every response status with its meaning, and a real example pair. Across endpoints: how a client uses them in order — create, poll, cancel — which is a sequence diagram, and the error contract. Chiltepin’s endpoint block holds the first; a sequence block holds the second.
- I already have an OpenAPI spec. Do I need the agent?
- No: chiltepin sync openapi spec.yaml --out docs/api.md generates the endpoint blocks straight from the spec, and --check fails CI when the doc and the spec drift. The agent adds what a spec does not have — the sequence of calls, the idempotency story, the callout about rate limits — around the generated blocks.
- How does the agent know the real routes?
- It reads them. With the skill installed, point it at the router directory and it names the actual paths, params and status codes from the handlers. Ask it to run the tests or fixtures for example payloads. Everything it writes is then checked for shape by chiltepin check, and for truth by your review of the diff.
- Can the doc render as a reference site?
- chiltepin build produces a static site with navigation and a search-free index; each endpoint gets a stable anchor from its id, so a link like docs/api/orders#post-orders survives rebuilds. The output has no runtime JavaScript, so it deploys anywhere static files do.