River
Y CombinatorBacked by Y Combinator

Free template

API Documentation and Reference Template

The quickstart, authentication guide, endpoint pages, error reference and changelog an API needs, plus sheets that track missing errors and broken examples.

Free download · No account needed

What you get

Pack of 10 files: 7 documents, 3 spreadsheets

API Documentation and Reference Template
  • Documentation StandardDocument
  • Reading a SpecificationDocument
  • Getting StartedDocument
  • Authentication GuideDocument
  • Endpoint ReferenceDocument
  • Error ReferenceDocument
  • ChangelogDocument
  • Endpoint RegisterSpreadsheet
  • Example Coverage CheckSpreadsheet
  • Problem Type RegisterSpreadsheet

How to write API documentation

API documentation is the set of pages a developer needs to use your API without asking you. It usually includes a quickstart, an authentication guide, a reference page for every endpoint, an error reference and a changelog. Good API documentation is complete and accurate: every endpoint and known failure is listed, every example works as printed, and each error tells the caller what to do next.

Document what your API actually does, not only what its spec file declares. The two drift apart, and developers find the gaps by hitting them.

A software engineer at an office desk works on a laptop in front of two monitors showing code
Check the docs against what the code actually does. Photo: ThisisEngineering on Unsplash

What API documentation includes

Each part answers a different question, so keep them apart. A quickstart teaches a newcomer; a reference page describes one endpoint completely. Daniele Procida, who created the Diátaxis documentation framework, warns that too many software developers think that auto-generated reference material is all the documentation required1.

The parts of a complete set of API docs

PartWhat goes in itCommon gap
QuickstartA key and the first two or three calls, ready to copySkips the error most newcomers hit first
AuthenticationKey types, scopes, rotation and webhook signaturesNo word on which scope each call needs
Endpoint referenceOne page per endpoint, in the same order every timeShows only the success response
Error referenceOne entry per error type, with its cause and fixOne row per status code
ChangelogEvery change a working integration could notice, datedDeprecations with no date or replacement

Start from the spec, then fill its gaps

If you have an OpenAPI file, use it as your inventory, but know its limits. In the OpenAPI Specification, a list of responses needs only one response code2, and a lone code should be the success response. So a spec file can be valid while declaring no errors at all.

The specification still expects documentation to cover "a successful operation response and any known errors." A catch-all default response with a one-line description falls short: it tells readers that failures exist, not what they look like. A linter can flag the gap. Redocly, which sells API documentation tools, has a rule in its recommended settings that warns when an operation has no 4xx error response3.

Then compare the file with what's running: your routes, your gateway config and a week of access logs. An endpoint that shipped without making it into the spec is invisible to every generator. Add each one you find, or mark it internal.

Write every endpoint page the same way

Developers learn where to look once, so give every endpoint page the same order. Define shared fields once, too: if a field like status appears on several endpoints, explain it in one place, such as a data dictionary, and link to it.

  • Summary: one sentence on what the call does
  • Authentication: the scheme and the exact scope it needs
  • Parameters: type, whether required, and units
  • Request and response examples that work as printed
  • Errors: every type the call can return
  • Rate limit, and what happens when a client hits it
ExamplePart of an endpoint pageAn illustrative example written for this guide, using the made-up shipping API in the template's files.

POST /v1/shipments buys a shipping label for a rate you quoted earlier. It needs a key with the shipments:write scope and allows 60 requests a minute.

Send an Idempotency-Key header with every request, so a retry returns the first label instead of buying a second one.

Errors: rate-expired (409), label-already-generated (409), insufficient-postage-balance (402) and carrier-account-suspended (403), each linked to its entry in the error reference.

  • The scope is named. A key that can quote rates but not buy labels fails here, so the page says which scope it needs.
  • Errors by type. Two errors share a 409, so each is named by type and links to its own fix.

Check that every example works

Examples are what developers copy, so one that doesn't match its schema breaks their code. OpenAPI says an example should be compatible with its schema2, and leaves tools free to check or not. If nothing checks, an example can keep showing a field you renamed months ago.

Spectral, an open-source linter from the API design company Stoplight, checks examples against their schemas4 in its recommended OpenAPI rules and reports a mismatch as an error. Run a check like it on every pull request.

Valid isn't the same as working. An example can match its schema and still fail when sent, because an ID in it has expired or the record it creates already exists. Send each one to a sandbox before you publish, and keep one example per request or response so two copies can't disagree.

Document errors by type, not status code

One status code often covers several errors that need different handling. RFC 9457, the IETF standard for error details in HTTP APIs, gives each kind of error a type URI. It says consumers must use that URI as the problem type's primary identifier5, and treats the status in the body as advisory.

For each error type, the RFC says you must document a type URI, a short title and the status code it goes with. Add the extra fields it carries, what causes it and what the caller should do. The RFC adds that a type URI should lead to documentation on resolving the problem, so make each one open its own entry in your error reference.

Error types from the template's sample shipping API

Error typeStatusWhat the caller should do
rate-expired409Get a new quote, then retry once
label-already-generated409Stop retrying and fetch the existing label
insufficient-postage-balance402Top up the balance, then retry
about:blank (no specific type)404Stop: this account has no shipment with that ID

Code that branches on 409 alone can't tell the first two apart.

Don't invent a type for everything. The RFC says truly generic problems are usually better expressed as plain status codes. A response with no type counts as about:blank, which means the status code says it all, so use it only where that's true.

Write the quickstart last

Write the quickstart once the reference and errors are settled, so it can link to them. Postman, which sells API tools, says the most important API metric is time to first call6: how long a new developer takes to make a first successful request.

Keep it to the few calls that produce something real, each ready to copy, with the response it returns. List the scopes the key needs before the first call, and show the failure newcomers hit most, with its fix. Then hand it to a colleague who has never used the API, and time them.

Record every change a client could notice

Add a dated changelog entry for anything a working integration could notice: a new required field, a removed field, a new error, a changed limit or a corrected example. Say who is affected and what they need to do.

Deprecations need the most care. OpenAPI's deprecated field2 is only true or false, with no room for a date or a replacement, so put those in the changelog. RFC 97457, published in March 2025, defines a Deprecation response header that warns clients at runtime. A Sunset header can add the date the endpoint stops responding.

Before you publish

  • Every live endpoint is in the spec, or marked internal
  • Every endpoint lists its known errors, not just a default
  • Every example validates against its schema and runs in the sandbox
  • Every error type has a URI that opens its own entry
  • The quickstart reaches a successful call and shows the common failure
  • Every deprecation has a date, a replacement and a migration note

The template on this page has each of these documents filled in for a made-up shipping API, plus sheets that track endpoints, examples and error types. When a release ships, turn your commits into release notes, and keep the history in a release notes and changelog template.

How to use this template

Start with the Documentation Standard, which suggests a default for each rule your team needs to settle, then fill the three registers before you write the published pages. The sheets and published documents come filled in for Waypost, a made-up shipping API, so you can see how they fit together.

Or open it in River with Edit with AI and send your OpenAPI or Swagger file, plus error-handling code or logs if you have them. River fills the endpoint register, checks each example against its schema, lists the error types your API really returns, and reports what the spec leaves out.

  1. Download it or open it in River

    Get the seven Word documents and three CSV sheets free, or open the template in River to work through it with AI.

  2. Send your spec and error logs

    Attach an OpenAPI or Swagger file, a URL or a Postman collection, plus error-handling code or recent error logs if you have them.

  3. Get the registers filled in

    River counts each endpoint's declared errors, checks every example against its schema and lists each error type your API returns.

  4. Fix the biggest gaps first

    River suggests which findings to fix first. Then ask it to write the error reference, the quickstart or a changelog entry.

What's in the template

The operation that declares no failure, and the example nobody validatedEvery state in these three sheets is one a conforming OpenAPI document is allowed to be in. Default lint rules flag only a few of them.
API Documentation and Reference Template
RiverEndpoint Register

Endpoint Register

Illustrative rows for a fictional parcel shipping API, Waypost.

OperationStatusResponses declaredErrors declaredExamples presentExamples validatingOwner
POST /v1/ratespublished200, 400, 422, 4293 of 42 of 22 of 2Priya N
POST /v1/shipmentspublished201 only0 of 11 of 10 of 1Tomas K
GET /v1/shipments/{id}published200, 404, default1 of 2, plus a bare default1 of 11 of 1Tomas K
DELETE /v1/shipments/{id}partial204, 409, 4222 of 30 of 0n/a, none presentTomas K
GET /v1/tracking/{number}partial200, 404, 4292 of 31 of 10 of 1Ada W
POST /v1/labelsundocumentednot in the specificationunknown0 of 0n/aunowned
POST /v1/webhooksdeprecated201, 400, 4092 of 31 of 11 of 1Ada W
GET /internal/v1/rate-cardsinternal, published by mistake200, 4031 of 21 of 11 of 1Priya N

Row two is a conforming specification. The Responses Object needs one response code and the guidance is that a lone code should be the successful one, so a document declaring only a 201 passes validation. That operation returns four distinct failures in production and the generated reference page shows one green row.

A bare default is never credited as an error. Row three declares a default with a description and no schema, which is exactly what the specification permits. It renders as a row telling a reader that failures exist and nothing about their shape, and every 5xx lands there undifferentiated.

Row six is in the router and not in the document. No generator can report it, because a tool cannot see what is missing from its own input.

RiverExample Coverage

Example Coverage Check

Present, validates and runs are three separate columns. A build checks the second only if it runs a lint rule for it.

OperationKindLives inPresentValidatesFirst failureOverridden byRuns
POST /v1/ratesrequestmedia typeyesyesnonenothingyes
GET /v1/tracking/{number}responsemedia typeyesnoevents is array<object> in the schema, array<string> in the examplenothingno
POST /v1/addresses/validaterequestschema objectyesyesnonethe media-type examplenever rendered
POST /v1/addresses/validaterequestmedia typeyesnosends postcode, schema requires postal_codenothing, this one winsno
POST /v1/shipmentsresponsemedia typeyesnorate_id required in the schema, absent from the examplenothingno
DELETE /v1/shipments/{id}responsenowherenon/an/an/an/a
GET /v1/shipments/{id}response, defaultnowherenon/an/an/an/a
POST /v1/webhooksrequestmedia typeyesyesnonenothingno, returns 409

The tracking example has been wrong for eleven months. In JSON Schema 2020-12 the examples keyword sits in the vocabulary for basic meta-data annotations, and validity against the associated schema is recommended rather than required. OpenAPI says an example should match its schema. The build runs no lint rule that checks examples, so nothing broke.

Rows three and four are the same field, twice. Under OpenAPI 3.0 and 3.1 a media-type example overrides a schema-level one, and the schema-level field is deprecated in the current specification version. The correct example is in the document and no reader can reach it; the stale one predates a field rename and is the one that renders.

The last row validates cleanly and returns a 409 when sent, because a schema cannot know that a webhook URL is already registered.

RiverProblem Types

Problem Type Register

One row per type URI, not per status code. Two of these share a 409.

TypeStatusExtension membersWhat to doURI resolvesIn spec
rate-expired409rate_id, quoted_at, expires_atRe-quote, retry once with the new rate_idyesno
label-already-generated409shipment_id, label_id, generated_atStop retrying. Fetch the existing labelyesno
address-unverifiable422field, suggested_value, confidenceShow the suggestion to the user. Never substitute ityesyes
insufficient-postage-balance402balance, required, top_up_urlTop up, then retry the same requestno, 404sno
carrier-unavailable503carrier, retry_after_secondsRetry after the delay, or re-quote excluding that carriernolands in the bare default
carrier-account-suspended403carrier, suspended_at, contactStop. Contact the carrier. Retrying never worksyesno
about:blank401, 404noneRefresh the token, or stop. Deliberateregistered by the standard404 only
(no type member sent)429none, plain JSON bodyHonour Retry-After. The window is fixedn/ayes

The first two rows are why a status-code table is the wrong artifact. Both return 409. Retrying the first usually succeeds and retrying the second never does, so code branching on the number produces a retry loop against an operation that buys postage. RFC 9457 requires consumers to use the type URI as the primary identifier and makes the status member advisory.

Row four returns a type URI that 404s. The standard says dereferencing a locator type URI should provide human-readable documentation for the problem type, so this is a promise made on the API’s behalf and broken. It is also the cheapest row here to fix.

The last row sends no type member, so its type is assumed to be about:blank, which claims the status code carries the whole meaning. On a 429 with a retry window, it does not.

  • Documentation StandardEleven decisions with suggested defaults, from what counts as published to who owns each area.
  • Reading a SpecificationThe rules from OpenAPI, JSON Schema and RFC 9457 behind each register column, quoted from the sources.
  • Getting StartedA three-call quickstart for a sample shipping API, with the failures newcomers hit and how to handle them.
  • Authentication GuideKey types, scopes, rotation, idempotency keys and how to verify webhook signatures.
  • Endpoint ReferenceTwo finished endpoint pages in a fixed order, and three unfinished ones with what each lacks.
  • Error ReferenceOne entry per error type: its URI, status, extra fields, cause and what the caller should do.
  • ChangelogDated entries for every change a client could notice, with deprecation dates and replacements.
  • Endpoint Register sheetOne row per endpoint and method: declared responses and errors, examples, auth, rate limit and owner.
  • Example Coverage Check sheetOne row per example: where it lives, whether it validates, its first failure and whether it runs.
  • Problem Type Register sheetOne row per error type URI, with status, extra fields, cause, the fix and whether it's documented.

Common questions

What should an API documentation template include?

A quickstart, an authentication guide, one reference page per endpoint, an error reference and a changelog. Each endpoint page needs its parameters, a working request and response example, every error it can return and its rate limit. This template adds three sheets that show which endpoints, examples and error types are still incomplete.

Can I generate API documentation from an OpenAPI file?

Yes, for the reference pages, but a generator can only show what the file declares. OpenAPI accepts a file that lists one success response per operation, so errors you never declared won't appear, and neither will endpoints missing from the file. The quickstart, error reference and changelog still need someone who knows how the API behaves.

How should API errors be documented?

Give each kind of error its own entry, keyed by a type rather than by status code, because two errors can share a status and need opposite handling. RFC 9457 sets the standard format. Each entry needs the type URI, a short title, the status, any extra fields, the cause and what the caller should do.

How do you keep API documentation up to date?

Keep the spec in the same repository as the code, and check it on every pull request. Lint it, validate each example against its schema, and compare it with your routes. Add a changelog entry with each release that changes anything a client could notice, and update the error reference whenever a new error ships.

Is this API documentation template free?

Yes. Download the seven Word documents and three CSV sheets with no signup. They come filled in for Waypost, a made-up shipping API, so you can see a finished set before you swap in your own endpoints. Edit with AI opens the same template in River.

What does Edit with AI do?

It opens the template in a free River workspace, where River asks for your spec and any error logs or error-handling code. It records every endpoint with its declared errors, validates each example against its schema and builds the error type register from what your API returns. It never invents an error your API doesn't return.

Sources

  1. Diátaxis. “Reference.” diataxis.fr (opens in a new tab)

  2. OpenAPI Initiative. “OpenAPI Specification v3.2.1.” spec.openapis.org (opens in a new tab)

  3. Redocly. “operation-4xx-response.” redocly.com (opens in a new tab)

  4. Stoplight. “OpenAPI Rules.” github.com (opens in a new tab)

  5. RFC Editor. “RFC 9457: Problem Details for HTTP APIs.” rfc-editor.org (opens in a new tab)

  6. Postman. “Improve Your Time to First API Call by 20x.” blog.postman.com (opens in a new tab)

  7. RFC Editor. “RFC 9745: The Deprecation HTTP Response Header Field.” rfc-editor.org (opens in a new tab)

Written by

Chandler Supple

Co-founder & CEO, River

Chandler has spent the last six years working in AI, building tools for millions of users and Fortune 100 companies. In 2025, he co-founded River to build a new kind of operating system for AI agents.

Reviewed by

Brian Joseff, Co-founder, River