# How to read this site

Three tiers on every concept, a copyable link on every section, and a rule about numbers that explains why almost nothing here is typed by hand.

**What this covers:** The three tiers; Linking to one section; Why almost no number on this site is typed by hand; Telling us a page is wrong.

**Assumed knowledge:** Nothing.

**Canonical HTML:** https://jobopportunitiesapi.org/docs/conventions  
**Machine-readable index:** https://jobopportunitiesapi.org/docs/ai/index.md  
**Last verified:** 2026-08-22  
**Superseded by:** the live API at https://api.jobopportunitiesapi.org and its spec at https://jobopportunitiesapi.org/openapi.json — where this file and the API disagree, the API is right.

---

<a id="how-to-read"></a>

## 1. The three tiers

Every documented concept has a one-line summary that is always visible, and two expandable tiers under it: the prose, then the exact contract.

### 1.1 In depth

The structure exists because three different people read the same page. Someone skimming wants to know what a thing *is* without opening anything. Someone deciding whether this product fits wants the reasoning — why it exists, what it is not, what people get wrong about it. Someone implementing wants types, defaults, ranges, error codes and edge cases, and wants the prose out of the way.

Serving all three with one register produces a page that is too long for the first reader and too vague for the third. So the summary is always visible, and the other two are one click each.

- **Always visible** — One sentence, under 150 characters, no jargon. What the thing is, in one breath.
- ****In depth** (expandable)** — Why it exists, how it fits, what it is not, what people get wrong, when you would and would not use it.
- ****Exact contract** (expandable)** — Types, defaults, ranges, enums, nullability, error codes, interactions, performance.
- **Worked examples** — Always visible, below the tiers — a reader who understood the sentence usually wants the command next, not more prose.

### 1.2 Exact contract

The expandable tiers are native `<details>` / `<summary>` elements. That is a deliberate implementation choice with three consequences: the page works with JavaScript disabled; the browser's own find-in-page can open a collapsed section when the match is inside it; and — most importantly — the full text of every tier is present in the served HTML rather than fetched on expansion, so a crawler or an AI agent reading the raw HTML receives everything without executing anything.

Both tiers open automatically when the page is loaded with a fragment pointing inside them, so a deep link never lands a reader on a collapsed section.

**See also**

- [Linking to one section](./conventions.md#deep-links)
- [The machine-readable mirror](./for-agents.md#agents-start-here)

<a id="deep-links"></a>

## 2. Linking to one section

Every section has a § button that copies its permanent link. There is also a shorthand: /docs?s=<section-id> resolves to whichever page owns that id.

### 2.1 In depth

Section ids are globally unique across the whole site and are checked for uniqueness when the site is built — two sections claiming the same id fails the build rather than producing an ambiguous link. Ids are stable: they are never renumbered, and a retired one is not reused.

The canonical form of a deep link is a path and a fragment, because that is the form search engines index and the form a browser resolves without a round trip. The `?s=` form is a convenience for typing and for citing a section whose page you do not remember — it looks the id up and redirects.

### 2.2 Exact contract

| Form | Example | What happens |
| --- | --- | --- |
| Canonical | `/docs/api/parameters#country-codes` | Loads the page, opens the section, scrolls to it. No redirect. |
| Shorthand | `/docs?s=country-codes` | Resolves the id and redirects (308) to the canonical form. |
| Unknown id | `/docs?s=nonsense` | Falls through to the documentation home page with the search box focused. |
| Markdown mirror | `/docs/ai/api-parameters.md#country-codes` | The same section in the machine-readable copy. |

The `?s=` form is not the one the § button copies, and deliberately so: `web/src/app/robots.ts` disallows `/*?` for every crawler, because this site's front page exposes a combinatorial facet space that once held a server process at 96% CPU for as long as a crawler kept enumerating it. A documentation link carrying a query string would inherit that blanket refusal and would never be indexed.

**See also**

- [The three tiers](./conventions.md#how-to-read)
- [The crawler policy](./website-legal.md#site-robots)

<a id="doc-freshness"></a>

## 3. Why almost no number on this site is typed by hand

Every figure here is rendered from the endpoint that owns it, printed with the instant it was measured, next to a link to fetch it yourself.

### 3.1 In depth

This product's entire pitch is that its claims are checkable. A stale number in its own documentation is therefore not a cosmetic bug — it is a defect in the thing being sold. That is not hypothetical here: a batch of outreach drafts written against hand-copied figures were wrong by up to a factor of four within a week.

So the rule is: **link the endpoint, never quote the number.** Coverage figures come from `/public/coverage`. The country table comes from `/public/coverage/countries`. The provider list comes from `/public/providers`. Prices and limits come from `/public/plans`. Parameter and field tables are generated from `/openapi.json`, which is itself rendered by the running API rather than checked in beside it.

> **This page is only as fresh as its last build** — The figures are re-fetched when the page is regenerated, not on every request. Each one prints its `measured_at` so you can see how old it is, and links the endpoint so you can get today's. If a figure here and the endpoint disagree, the endpoint is right.

### 3.2 Exact contract

Where a figure genuinely cannot be rendered — because the endpoint could not be read when the page was built — the page says so and links the endpoint, rather than printing a zero. A zero is a lie with a number on it, and this site would rather show a gap.

The same discipline applies to examples. Every request published on this site is extracted from the source and sent against the live API before the site is allowed to build. This is not a manual review step, it is a gate in `ops/build-web.sh`: if a documented request stops answering 2xx, the build fails and nothing ships. It exists because on 2026-08-16 the first external evaluator this product ever had copied an example from the old documentation and got a 422 — the API was right, the vocabulary check was right, and the documentation was the only thing wrong.

**See also**

- [The coverage report](./ledger-coverage.md#coverage-report)
- [Controlled vocabularies — never hard-code these](./api-parameters.md#filter-vocabularies)

<a id="feedback-loop"></a>

## 4. Telling us a page is wrong

Every page has a thumbs-up and a thumbs-down at the foot. A thumbs-down opens a box, and what you write is read by the person who maintains these pages.

### 4.1 In depth

The counters are per page and are shown to you after you vote, so you can see whether a page is generally working for people. Nothing about you is recorded: no account, no email address unless you type one, no cookie beyond the one that stops a single browser voting on the same page repeatedly.

The most useful thing you can put in the box is the specific sentence that is wrong, or the request you sent and what came back. A documentation defect that comes with a reproduction gets fixed the same day; “this is confusing” takes longer, though it is still worth sending.

### 4.2 Exact contract

- **Where it goes** — A file on the server, with the page slug and the section anchor you were on, read directly by the maintainer's own mail client. Nothing is emailed — a relay that can fail quietly is a worse home for feedback than a file that cannot.
- **What is stored** — A per-page tally of up and down votes, and the text of any comment. No IP address, no user agent, no identifier for you.
- **Cookie** — One first-party cookie recording which pages this browser has voted on, so the tally is not a click counter. It carries no identifier and is not sent to the API.
- **If you would rather write** — [/contact](https://jobopportunitiesapi.org/contact) has a form with a `documentation` topic, and `hello@jobopportunitiesapi.org` is a real mailbox with a human on it.
- **Retention** — The last 2,000 comments. There is no copy anywhere else, so nothing is quietly discarded — but nothing is kept forever either.

**See also**

- [Every form, and where it posts](./website-pages.md#site-forms)

---

## Where to go next

This file is part of **Start here**. Others in the same group:

- [Overview](./overview.md) — What the Job Opportunities API is, what it deliberately is not, and the ten minutes of reading that will save you the most time.
- [Quickstart](./quickstart.md) — From nothing to a real response in one command, and to an authenticated one in about a minute. No card at any point.
- [If you are a program](./for-agents.md) — This documentation has a plain-Markdown mirror with no JavaScript, no redirects and no browser required. Here is where it is and what is in it.

Always useful:

- [index.md](./index.md) — the map of every file here
- [BUILD-A-SITE.md](./BUILD-A-SITE.md) — the paste-whole brief for building against this API
- [quickstart.md](./quickstart.md) — zero to a first authenticated response
- [api-errors.md](./api-errors.md) — every status code and whether to retry it
