# If you are a program

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.

**What this covers:** The machine-readable mirror; What is in the mirror; The rules that matter most to a program; The paste-whole brief.

**Assumed knowledge:** That you fetch URLs and read text. Nothing about JOA.

**Canonical HTML:** https://jobopportunitiesapi.org/docs/for-agents  
**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.

---

> **One file, if you only read one** — [/docs/ai/BUILD-A-SITE.md](./BUILD-A-SITE.md) is self-contained: the base URL, the auth header, the endpoints, the pagination contract, the error codes, the field list and worked code. It is written to be pasted whole into a model's context.

---

<a id="agents-start-here"></a>

## 1. The machine-readable mirror

Every page here also exists as Markdown under /docs/ai/, served as text/markdown, rendered from the same source as the HTML so the two cannot drift.

### 1.1 In depth

There are two audiences for this documentation and only one set of words. The HTML pages and the Markdown files are rendered from the same content modules in the site's source, so a paragraph added to one is added to both, in the same commit, or the build fails. A hand-maintained second copy would have diverged within a fortnight; this one cannot.

The directory is flat and one level deep. Files cross-link with relative names (`./api-errors.md`), so a fetcher can follow them mechanically without resolving anything. Every file opens with what it covers and what it assumes, and closes with the three to six files most likely wanted next — because the realistic case is that you fetch exactly one.

### 1.2 Exact contract

- **Entry point** — `https://jobopportunitiesapi.org/docs/ai/index.md` — a map of every file with a one-line summary of every section.
- **Content type** — `text/markdown; charset=utf-8`.
- **Caching** — `public, max-age=900` — the figures inside are re-rendered from the live endpoints on that cycle.
- **Redirects** — None. Every URL under `/docs/ai/` is terminal.
- **JavaScript** — None. The bytes you receive are the whole document.
- **Robots** — Allowed for search engines, answer engines and unfurlers alike. The docs are a selling page, not the corpus.
- **Freshness** — Each file carries a `Last verified:` date and names the endpoint that supersedes it.

The same content is in the HTML, too. The expandable tiers on every page are native `<details>` elements whose contents are present in the served HTML — they are not fetched on expansion. So an agent parsing the HTML receives the deep technical tier without executing anything or clicking anything.

### 1.3 Worked examples

Fetch the map

```console
$ curl -s https://jobopportunitiesapi.org/docs/ai/index.md | head -40
# Job Opportunities API — machine-readable documentation

Every page of https://jobopportunitiesapi.org/docs, as plain Markdown, served as
`text/markdown; charset=utf-8` with no JavaScript and no redirects. …
```

_Truncated. The real file lists every page and every section on the site._

**See also**

- [What is in the mirror](./for-agents.md#agents-files)
- [The rules that matter most to a program](./for-agents.md#agents-rules)

<a id="agents-files"></a>

## 2. What is in the mirror

One file per documentation page, plus an index, a paste-whole build brief, and a dated changelog so you can tell how old your copy is.

### 2.1 In depth

| File | What it is for |
| --- | --- |
| `index.md` | The map. Every file, every section, each with its one-line summary. |
| `BUILD-A-SITE.md` | Self-contained brief: everything needed to build a working integration, in one file. |
| `CHANGELOG.md` | Dated changes to this documentation. |
| `quickstart.md` | Zero to a first authenticated response. |
| `api-authentication.md` | Keys, the tolerant header, keyless access, rotation. |
| `api-rate-limits.md` | Per-plan limits, keyless limits, headers, backoff. |
| `api-pagination.md` | Cursors, the opaque-token rule, resumable pulls. |
| `api-errors.md` | Every status code, its JSON shape, and whether to retry. |
| `api-parameters.md` | The full parameter reference, generated from the OpenAPI spec. |
| `api-fields.md` | Every field on a job and a company, with type and nullability. |
| `ledger-data-model.md` | live + withheld + closed, and how they reconcile. |
| `ledger-provenance.md` | `field_sources`, `require_fields`, and the deliberate 422. |
| `endpoints-*.md` | One file per endpoint family, with the full parameter table and worked calls. |
| `recipes-*.md` | Runnable programs: daily pulls, incremental sync, bulk export, enrichment. |

### 2.2 Exact contract

File names are the page slug with `/` replaced by `-`, plus `.md`. So the HTML page `/docs/api/parameters` is `/docs/ai/api-parameters.md`. That mapping is mechanical in both directions and is stated in `index.md` as well, so you do not have to infer it.

Beyond this documentation there are three other machine surfaces worth knowing: [/llms.txt](https://jobopportunitiesapi.org/llms.txt) is the short doorway that points here; [/openapi.json](https://jobopportunitiesapi.org/openapi.json) and [/openapi.yaml](https://jobopportunitiesapi.org/openapi.yaml) are the authoritative machine contract, keyless and rendered from the running API; and `GET /public/ai-prompt` returns an integration brief straight from the API host with no website involved.

**See also**

- [The rules that matter most to a program](./for-agents.md#agents-rules)
- [Every endpoint, in one table](./overview.md#map-of-the-api)

<a id="agents-rules"></a>

## 3. The rules that matter most to a program

Seven behaviours that separate an integration that works from one that looks like it works. Each is stated once, here, in the imperative.

### 3.1 In depth

1. **Use `https://api.jobopportunitiesapi.org`.** The website host is edge-protected and may answer a non-browser client with a challenge, which reads as a 403.
2. **Send `Authorization: Bearer <key>` on `/v1/*`. Send nothing on `/public/*`** — a key there is neither required nor useful.
3. **Pass `next_cursor` back verbatim.** Never parse it, never rebuild it, never assume its shape.
4. **Read `field_sources` before you trust a field.** `published` is the source's word; `inferred` is ours; `absent` means there is none.
5. **Do not retry a 402.** It means the month's record allowance is spent. Retry a 429 after `Retry-After` seconds.
6. **Enumerate vocabularies at run time** from `/public/facets` and `/public/providers`. An unknown value is a 422, not an empty page.
7. **Key company identity on `company_domain` where you have it.** Slugs are not stable, and a retired slug now **301s** to its replacement — every slug a company has ever held keeps resolving. Follow redirects (`curl -L`). Treat a 404 on a slug that used to work as “re-resolve”, not “gone”.

### 3.2 Exact contract

Two more that only show up at scale. `include_description=true` caps `limit` at 50 and is refused with a 422 above that rather than silently clamped — descriptions average about 2.5 KB, so a 200-row page would be a half-megabyte response. And `/v1/export` charges records as it writes them, so an abandoned export is still billed for what it delivered; if the allowance runs out mid-stream the **last line of the body** is an error object carrying the resume cursor, which means a consumer must check the final line rather than assume a clean end of stream.

**See also**

- [next_cursor is opaque — this is the rule that bites](./api-pagination.md#cursor-opacity)
- [402 — the licence, not the throttle](./api-errors.md#error-402)
- [GET /v1/export](./endpoints-export.md#endpoint-export)
- [Company slugs are not yet guaranteed stable](./endpoints-companies.md#slug-instability)

<a id="agents-worked-brief"></a>

## 4. The paste-whole brief

BUILD-A-SITE.md is the canonical integration brief. If you are being asked to build something against this API, that file is the whole answer.

### 4.1 In depth

It holds, in one document: the base URL and auth header; the endpoint list with what each returns; the pagination contract; the complete error table with retry guidance; the job and company field lists with types and nullability; the provenance model; the rate and record limits; and worked code in curl, Python and JavaScript that has been run against the live API.

> **One canonical copy** — The examples repository at [github.com/lucagiftzek/joa-examples](https://github.com/lucagiftzek/joa-examples) carries a `PROMPT.md` that covers the same ground. `BUILD-A-SITE.md` is the canonical one, because it is rendered from this site's content and therefore cannot be a version behind the API. Where they differ, this one is right.

### 4.2 Exact contract

Everything a model needs, in two fetches

```bash
curl -s https://jobopportunitiesapi.org/docs/ai/BUILD-A-SITE.md > joa-brief.md
curl -s https://jobopportunitiesapi.org/openapi.json      > joa-openapi.json
```

The spec is worth fetching alongside the brief because it is the contract, it is machine-validated, and it carries the parameter prose in full — including the long explanations of `require_fields`, `has_salary` and `include_poster_type` that no summary preserves.

**See also**

- [What is in the mirror](./for-agents.md#agents-files)
- [How to read these tables](./api-parameters.md#params-how-to-read)

---

## 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.
- [How to read this site](./conventions.md) — 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.

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
