---
title: 'API Reference'
source: 'https://academia.sh/en/courses/technical-writing/api-reference'
course: 'Technical Writing and Documentation'
language: en
updated: '2026-08-17T18:10:48+00:00'
license: 'CC BY-SA 4.0'
---

# API Reference

13 of the reference's 15 claims are bound to signature, and a hand-written reference is left at 0/15 by version six; a generated one is left at 13/15 at the same version, the 2 unrecoverable claims sit on the name surface, and because reference carries no example every one of its stale claims is silent.

The previous lesson measured three repository documents, and in none of them did the
signature share exceed half. The repository's most crowded signature pile sits
elsewhere. The second lesson left the interface reference at **2/15** by version two,
and the reason was not the writer's carelessness: **13** of the fifteen claims hung on
the fastest-changing surface.

This lesson takes that type on its own terms. First it establishes how a reference is
sectioned — endpoint, parameter, error — then it measures a single question: do these
claims have to be **hand-written?** If not, how many survive, and what exactly is left?

## The Reference's Three Sections

A reference is not written to be read, it is written to be looked up. The reader knows
what they are looking for and wants to confirm a single cell. This is why a reference's
layout is not narrative, it is a **table**; and being a table is not merely a style
choice — a table ensures every cell carries a single claim and makes its absence
noticeable. The table has three sections.

**Endpoint** gives the call's identity: the method, the path, and the variable parts
inside the path. **Parameter** gives every input's name, where it comes from, its type,
whether it is required, and its default. **Error** lists the ways the call can fail:
status code, error code, and the condition it returns under.

```text
# an entry from the invented product's interface reference
# example text, not executed

GET /measurement/{station}/summary
  this endpoint is referred to in the reference as "station summary"

  station    path parameter     string   required
  interval   query parameter    integer  default 60, lower bound 1
  format     query parameter    string   "plain" | "table"

  200  returns a summary object
  404  station-not-found     the given station is not defined
  422  interval-invalid      interval is below the lower bound
```

Nearly everything written in this entry is the interface's **shape**: the path pattern,
parameter names, types, defaults, status codes. Only two things are not shape — the name
the endpoint is referred to by in the reference, and the error codes' names. Both sit on
the **name** surface, and shortly they will turn into a result on their own.

## The Fields of a Parameter Line

A parameter line has to say six things, and missing one sends the reader to the source:
**name**, **location** (path, query, or body), **type**, **required**, **default**, and
**bound**. In the entry above, the `interval` line carries all six; the `format` line
carries no default, and the reader is left with the question "what happens if I do not
give one."

All six of these fields sit on the signature surface, so all six carry the risk of
going stale once every two versions. But there is a distinction among them: the first
four can be read from the source's declaration; **default** and **bound** most often
sit in the code's body and cannot be read from the declaration. This distinction
predetermines how much generation can recover; the measurement counts the six as a
whole, but in practice generation's scope starts exactly here.

There is also something the line deliberately does not carry: **why**. Why the
`interval` parameter's lower bound is one is not written in the reference, it is
written in the explanation. If it were written in both, it would sit in two places,
the two would go stale at two separate speeds, and the reader would not know which one
is current.

## Status Code and Error Code

The error section's two columns do not say the same thing, and confusing them is
costly. The **status code** classifies roughly: was the request wrong, was the
resource missing, did the server crash. The **error code** names a single specific
condition — `station-not-found` and `measurement-not-found` can return the same status
code, and the reader's next action is completely different for each.

A practical consequence follows: a client **branches on the error code, not the status
code.** So the reference's most heavily relied-upon cell is the one sitting, in this
measurement, on the **name** surface. It is small in number — two of fifteen claims —
but it is the claim code gets written against. When it goes stale, branching silently
enters the wrong path; no type error is thrown, no warning appears.

The error section is the weakest section in most references, and the reason is
measurable. The successful path is written once and exercised on every call; failure
paths wait to be written and no one calls them. Yet the reader looking at a reference is
usually someone who has **already hit an error**; the cell they are looking for sits
exactly there.

Defining a contract in a machine-readable form and verifying it with a test are the
subject of the Web API Design course and are not repeated here. In this lesson the
reference is measured not as a contract tool but as **a text that needs maintenance**:
how many claims it carries, how much it holds up, how many of them can be recovered.

## Writing by Hand and Generating

The same reference can be brought into existence two ways.

In a **hand-written** reference, every cell is a sentence written by a person. When a
parameter's type changes in the source, the reference's cell keeps showing the old
type; nothing binds the two together. In a **source-generated** reference, the cells
sit not in prose but inside the source itself, and are reread on every publish. If the
type changes, the cell changes with it, because the cell is already a copy of the
source.

What generation recovers is fixed: **only what is written in the source.** A
parameter's name, type, and default are in the source. The name an endpoint is referred
to by in the reference is not in the source; an error code's human-readable name most
often is not either. These stay outside generation and remain in hand-written text. The
measurement gives this distinction as a number.

The measurement's assumptions:

- **DT27** — The measured set is the shared setup's **reference** type: **15** claims,
  **13** on signature, **2** on name. This mix is not changed.
- **DT28** — The reference has **no** flow or concept claim. Reference does not narrate
  order and builds no reasoning; this comes from the type's definition, not a choice
  made in this lesson.
- **DT29** — The fifteen claims are split across three sections: endpoint **4**,
  parameter **7**, error **4**. Sectioning does not change the surface mix, it only
  makes claims addressable.
- **DT30** — The reference's share of claims embedded in a runnable example is
  **0.00**. Reference carries no example; this is why every stale reference claim is
  **silent**.
- **DT31** — Surface frequencies are unchanged: signature every **2**, flow every
  **3**, name every **5**, concept every **12** versions.
- **DT32** — **In a generated reference, signature claims never go stale.** Because
  they are read from the source, they change together with it; the lag between the two
  is counted as zero in this measurement.
- **DT33** — Generation does not recover the **name** surface: the name an endpoint is
  referred to by, and an error code's readable name, do not sit in the source, they sit
  in hand-written text.
- **DT34** — Generation does not recover the **flow** surface either; but this cannot
  be measured in this reference, because the reference has no flow claim. Claims bound
  to flow are measured in the other types.
- **DT35** — The measurement builds versions **0, 1, 2, 3, 5, 6, and 12**.
- **DT36** — The set's resolution is **1/15**; differences below one claim cannot be
  defended with this set.

## Measurement

```python
"""API reference: the lifespan of the hand-written versus the generated.

Part 1 - how the reference's 15 claims split across sections and surfaces.
Part 2 - true/stale/silent across versions for hand-written versus generated reference.
"""
FREQUENCY = {"signature": 2, "flow": 3, "name": 5, "concept": 12}
VERSIONS = (0, 1, 2, 3, 5, 6, 12)
# The reference's 15 claims: which section, which surface they are bound to.
# Total signature 13, name 2 - exactly the reference mix from the shared setup.
SECTIONS = {
    "endpoint":  {"signature": 3, "name": 1},
    "parameter": {"signature": 7, "name": 0},
    "error":     {"signature": 3, "name": 1},
}
# The reference's embedded claim share is zero: reference carries no runnable example.
EMBEDDED = 0.00


def claims():
    entries, no = [], 0
    for section, mix in SECTIONS.items():
        for surface, count in mix.items():
            for _ in range(count):
                no += 1
                entries.append({"no": no, "section": section, "surface": surface,
                                 "embedded": EMBEDDED >= 1})
    return entries


def stale(i, version):
    return version // FREQUENCY[i["surface"]] >= 1


def measure(entries, version, generated):
    """In a generated reference, signature claims come from the source and never go stale."""
    gone_stale = [i for i in entries
                  if stale(i, version) and not (generated and i["surface"] == "signature")]
    silent = [i for i in gone_stale if not i["embedded"]]
    return len(entries), len(entries) - len(gone_stale), len(gone_stale), len(silent)


L = claims()
print(f"reference claims {len(L)} | embedded in example "
      f"{sum(i['embedded'] for i in L)}")
print()
print(f"{'section':<12s} {'claims':>6s} {'signature':>9s} {'name':>4s} {'flow':>5s} "
      f"{'concept':>7s}")
for b in SECTIONS:
    g = [i for i in L if i["section"] == b]
    print(f"{b:<12s} {len(g):6d} "
          + " ".join(f"{sum(1 for i in g if i['surface'] == y):>{w}d}"
                     for y, w in zip(("signature", "name", "flow", "concept"),
                                     (9, 4, 5, 7))))
print(f"{'total':<12s} {len(L):6d} "
      + " ".join(f"{sum(1 for i in L if i['surface'] == y):>{w}d}"
                 for y, w in zip(("signature", "name", "flow", "concept"),
                                 (9, 4, 5, 7))))

print()
print(f"{'version':>7s} {'hand-written':>20s} {'generated':>20s}")
print(f"{'':7s} {'true/stale/silent':>20s} {'true/stale/silent':>20s}")
for s in VERSIONS:
    h = measure(L, s, False)
    g = measure(L, s, True)
    print(f"{s:7d} {'{}/{}/{}'.format(*h[1:]):>20s} "
          f"{'{}/{}/{}'.format(*g[1:]):>20s}")

print()
print(f"{'section':<12s} {'v6 hand-written':>15s} {'v6 generated':>13s} "
      f"{'recovered':>9s}")
for b in SECTIONS:
    g = [i for i in L if i["section"] == b]
    h, gen = measure(g, 6, False), measure(g, 6, True)
    print(f"{b:<12s} {f'{h[1]}/{h[0]}':>15s} {f'{gen[1]}/{gen[0]}':>13s} "
          f"{gen[1] - h[1]:9d}")

print()
remaining = [i for i in L if stale(i, 6) and i["surface"] != "signature"]
print("stale claims remaining in the generated reference at version 6:",
      [(i["section"], i["surface"]) for i in remaining])
print(f"surface recovered by generation: signature "
      f"({sum(1 for i in L if i['surface'] == 'signature')} claims) | not recovered: "
      f"{', '.join(sorted({i['surface'] for i in remaining}))} ({len(remaining)} claims)")
```

```
reference claims 15 | embedded in example 0

section      claims signature name  flow concept
endpoint          4         3    1     0       0
parameter         7         7    0     0       0
error             4         3    1     0       0
total            15        13    2     0       0

version         hand-written            generated
           true/stale/silent    true/stale/silent
      0               15/0/0               15/0/0
      1               15/0/0               15/0/0
      2              2/13/13               15/0/0
      3              2/13/13               15/0/0
      5              0/15/15               13/2/2
      6              0/15/15               13/2/2
     12              0/15/15               13/2/2

section      v6 hand-written  v6 generated recovered
endpoint                 0/4           3/4         3
parameter                0/7           7/7         7
error                    0/4           3/4         3

stale claims remaining in the generated reference at version 6: [('endpoint', 'name'), ('error', 'name')]
surface recovered by generation: signature (13 claims) | not recovered: name (2 claims)
```

## What Generation Recovers and What It Does Not

The middle table gives the lesson's main number. By version six, the hand-written
reference is at **0/15**; not a single claim is recovered, all fifteen of fifteen are
stale. The generated reference at the same version is at **13/15**. The difference is
**13** claims, and all of it comes from the **signature cells of parameter and
endpoint**.

The bottom table spreads the difference across the sections: the parameter section
goes from **0/7** hand-written to **7/7** generated — fully recovered, because every
cell inside it is written in the source. Endpoint climbs from **0/4** to **3/4**, error
from **0/4** to **3/4**. Both sections are left with one unrecoverable claim.

The last row states plainly which two claims cannot be recovered: one is the endpoint's
**name** in the reference, the other is the error code's readable **name**. Both sit on
the **name surface**. Generation's boundary is drawn cleanly here: **generation
recovers what is written in the source, it does not recover what a human made up.** The
source does not decide what a name should be.

The same boundary applies to the **flow** surface too — the order calls must be made
in cannot be generated from the source either — but it cannot be measured in this
reference, because the reference's flow claim count is **0**. This is not a
measurement gap, it is the type's definition: reference does not narrate order. It is
also the reference's biggest blind spot, and this topic's sixth lesson enters exactly
there.

The silent column is the lesson's uncomfortable finding. Because the reference's
embedded claim count is **0**, the stale count and the silent count are **identical**
on every row: **15/15** hand-written, **2/2** generated. So generation brings the stale
count down from fifteen to two but **does not change the silence ratio at all** — the
remaining two claims still sit wrong without telling anyone anything.

This matters not to belittle generation but to name what it actually does correctly.
Generation is not a **document audit**, it is a **copying** mechanism: it forms the
link between source and text, it does not report the text's correctness to anyone.
Once thirteen claims are recovered, the remaining two are exactly as silent as before —
and since the rest of the reference is now trustworthy, no one is expected to look at
those two with suspicion either. **The recovered claims hide the unrecoverable ones.**

Which two claims specifically remain unrecoverable also matters. An earlier section
said the client branches on the error code, not the status code; one of the
unrecoverable claims is exactly that error code's name. So the **13/15** ratio makes
the practical recovery look better than it is: the thirteen claims recovered are the
cells the reader checks to confirm; the two unrecovered are the cells code is written
against. Read over the denominator, generation looks like it has recovered **0.8667**
of the set; read over impact, it has left the two most expensive claims exactly where
they were. The measure itself does not say this — it counts claims, not their
weight — and this is a limit of claim-counting worth knowing.

The version-two and version-three rows give one last detail: the generated reference
stands at **15/15** there, meaning it takes no loss at all through the first three
versions. The hand-written one is at **2/13/13** at the same point. Generation's gain
starts at the first signature change and stays **complete through version five**; the
name surface changes there for the first time, and the count drops from **15** to
**13**. After that it holds steady: still **13/15** at version twelve. The generated
reference stops decaying **any further** past a certain point, because it has already
broken everything it could.

## Summary

- Reference is a table, not narration; it has three sections — endpoint, parameter,
  error — and error is the weakest section because no one calls the failure paths.
- **13** of the reference's **15** claims are bound to signature, **2** to name; it has
  **no** flow or concept claim, and its embedded claim count is **0**.
- The hand-written reference gives **0/15** by version six; the source-generated one
  gives **13/15** at the same version. The difference comes from the parameter
  section's **7/7** recovery and two sections' **3/4** recovery.
- The **2** unrecoverable claims sit on the **name** surface — the endpoint's referred
  name and the error code's readable name; generation recovers what is written in the
  source, not what a human made up.
- Because reference carries no example, its stale count and silent count are equal on
  every row; generation brings stale down from **15** to **2** and changes the silence
  ratio **not at all**.
- The client branches on the **error code**, not the status code; one of the two
  unrecoverable claims is exactly that. Claim-counting does not weigh claims, and this
  is the measure's limit worth knowing.

## Next Step

Up to here, the four types and the repository documents described the product's
**current state**. This lesson's table left the reader owing a new question: with a
**13/15** reference in hand, how will they know **when** the remaining two dropped?
The second lesson had already named this question — "what version did this change in"
landed on no type. The next lesson measures the text that closes that gap: release
notes. The question will be — what difference does the list of changes make against
the list of what those changes **mean**, and how many claims does it make datable for
the reader?
