# Plans

What each plan includes, rendered from the live price list, and what actually distinguishes them — which is records and entitlements, not features.

**What this covers:** The plans; The two entitlements; Choosing one; Grant keys and the free tier.

**Assumed knowledge:** Nothing.

**Canonical HTML:** https://jobopportunitiesapi.org/docs/account/plans  
**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="plans-table"></a>

## 1. The plans

Every plan gets every REST endpoint. What changes up the ladder is the monthly record allowance, the request ceilings, and two entitlements.

### 1.1 In depth

There is no feature-gating of the data itself: the free plan queries the same live ledger, with the same fields and the same provenance, as the most expensive one. That is deliberate — a product whose pitch is auditability cannot ask you to pay to check its claims.

| plan | display_name | price | records_per_month | req_per_day | req_per_min | delta_feed | bulk_export | single_country |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| explore | Explore | Free | 1,000 | 5,000 | 30 | false | false | false |
| growth | Growth | €80/month | 60,000 | 100,000 | 120 | true | false | false |
| signal | Signal | €299/month | 400,000 | 400,000 | 300 | true | true | true |
| scale | Scale | €899/month | 2,000,000 | 1,000,000 | 600 | true | true | false |

_Generated from `GET https://api.jobopportunitiesapi.org/public/plans` (no key required). Only purchasable plans appear there._

This table comes from `/public/plans`, which lists only purchasable plans. If a plan is not here, you cannot buy it. Compare and buy at [/pricing](https://jobopportunitiesapi.org/pricing).

### 1.2 Exact contract

| Dimension | What it is | Where it bites |
| --- | --- | --- |
| `records_per_month` | **The licence.** How many rows you may receive in a month. | The real ceiling on almost every integration. Exhausting it is a [402](./api-errors.md#error-402). |
| `req_per_day` / `req_per_min` | Burst protection for the origin. | Rarely the binding constraint above the free tier. Exceeding it is a [429](./api-errors.md#error-table). |
| `delta_feed` | Entitlement: `/v1/changes` and `/v1/jobs/expired`. | Without it, keeping a mirror current means re-reading listings — far more records. |
| `bulk_export` | Entitlement: `/v1/export`. | Without it, a full-corpus pull means paging. |
| `single_country` | The country-locked SKU: one country, exempt from the record meter for job rows. | [Detail](./account-record-meter.md#country-locked). |
| max page size | The largest `limit` the plan allows. | A plan property, not a constant — and **not published on any endpoint**, so it can only be observed by counting the rows you get back. Requests above it are clamped rather than refused. |

> **Compare on records, not on requests** — A request-priced API and a record-priced one are not comparable line by line. Ten thousand requests a day at 200 rows a page is two million rows a day — which is why the licence here is on rows. [Why the meter is on records](./account-record-meter.md).

**See also**

- [The two entitlements](./account-plans.md#plan-entitlements)
- [What counts as a record](./account-record-meter.md#meter-what-counts)
- [When keyless stops being enough](./api-keyless.md#keyless-when-to-upgrade)

<a id="plan-entitlements"></a>

## 2. The two entitlements

delta_feed and bulk_export are the only endpoints a plan can lack. Missing one is a 403 that names it in a header.

### 2.1 In depth

A plan without `delta_feed` cannot call `/v1/changes` or `/v1/jobs/expired`. A plan without `bulk_export` cannot call `/v1/export`. Everything else is available on every plan, including the free one.

The refusal is explicit rather than silent: HTTP 403 with `X-JOA-Required-Feature: delta_feed` or `bulk_export`, so a client can report exactly what is missing rather than “forbidden”.

> **This gate is checked, not assumed** — Before it was enforced, the entitlement columns were read into every request and checked by nothing — a free key could walk the entire ledger through `/v1/changes`, unmetered. There is now a QA assertion per plan per endpoint, which is what stops that coming back silently.

### 2.2 Exact contract

What a plan without the entitlement sees

```bash
curl -s -D - -o /dev/null -H "Authorization: Bearer $EXPLORE_KEY" \
  'https://api.jobopportunitiesapi.org/v1/changes?since=2026-08-01T00:00:00Z&limit=2'
# HTTP/2 403
# x-joa-required-feature: delta_feed
```

`/v1/me` reports the plan but not the entitlements directly; the dashboard shows them per key as an **Includes** row, and `/public/plans` lists them per plan. In code, read `/public/plans` and match on your plan name rather than hard-coding which tier has what.

**See also**

- [GET /v1/changes](./endpoints-changes.md#endpoint-changes)
- [GET /v1/export](./endpoints-export.md#endpoint-export)
- [What a rejected key looks like](./api-authentication.md#auth-failure-modes)

<a id="plan-choose"></a>

## 3. Choosing one

Estimate records, not requests: rows you will receive per month, including every re-read. That number picks the plan.

### 3.1 In depth

1. **Count the rows in your slice.** `/public/coverage/countries` and `/public/facets` give you this keylessly, for free, before you buy anything.
2. **Decide how often you re-read them.** This is where most estimates go wrong. A daily full re-read of a 60,000-row slice is 1.8 million records a month; the same slice kept current with `/v1/changes` is a fraction of that.
3. **Add the seed.** The first full pull costs one record per row, once.
4. **Add a margin.** Development, retries and re-processing are all real records.
5. **Then pick the plan** whose `records_per_month` covers it, and check it has the entitlements your design needs.

If the answer is “a daily full re-read is too expensive”, the answer is usually not a bigger plan — it is [the delta feed](./endpoints-changes.md), which is specifically the tool for that problem and is included from Growth upward.

### 3.2 Exact contract

| Shape | Records per month, roughly | Notes |
| --- | --- | --- |
| Evaluation, by hand | hundreds | Or none at all — `/public/*` is keyless. |
| A niche board, one country + category, delta-synced | seed + what moves | The seed dominates in month one and then almost nothing. |
| A board over a whole country, daily full re-read | live rows × 30 | Usually the wrong architecture. Switch to the delta feed. |
| CRM enrichment, 5,000 domains weekly | rows returned × 4 | Cap `limit` to what you store. |
| Research corpus, one-off | the corpus, once | Use `/v1/export` — needs `bulk_export`. |
| Whole-ledger mirror, kept current | seed + daily changes | Needs `delta_feed`; `bulk_export` makes the seed far easier. |

Every one of these is measurable before you pay: run the query keylessly, look at the counts, and multiply. If you would rather have somebody check the arithmetic, [/contact](https://jobopportunitiesapi.org/contact) reaches a person.

**See also**

- [What counts as a record](./account-record-meter.md#meter-what-counts)
- [An incremental sync](./recipes-sync.md#recipe-incremental-sync)
- [Per-country coverage](./ledger-coverage.md#countries-list)

<a id="grant-keys"></a>

## 4. Grant keys and the free tier

The free Explore plan needs no card and does not expire. There is also a grant key for research and non-commercial work, by application.

### 4.1 In depth

**Explore** is not a trial. It has no expiry date, it needs no payment details, and it gives you every REST endpoint against the live ledger. What it does not have is the delta feed, bulk export, or a large record allowance.

**Grant** keys exist for research, journalism and non-commercial work: a larger record allowance than Explore and the delta feed, still at no cost. They are not on the price list because they are not purchasable — apply at [/contact?topic=grant](https://jobopportunitiesapi.org/contact?topic=grant) and say what you are building.

### 4.2 Exact contract

Because grant keys are not purchasable they do not appear on `/public/plans`, which lists active, buyable plans only. That is why a grant key's plan name may not match anything in the table on this page — read your own key's limits from `/v1/me` and the dashboard rather than from the price list.

You can hold several keys at once, on different plans. The record allowance is **per key**, not per account, so splitting environments across two keys also splits the meter — which is usually what you want, since it stops a runaway staging job from spending production's allowance.

**See also**

- [Step two — get a key](./quickstart.md#qs-get-key)
- [Creating, naming, rotating and revoking](./api-authentication.md#auth-keys-lifecycle)
- [What counts as a record](./account-record-meter.md#meter-what-counts)

---

## Where to go next

This file is part of **Account & billing**. Others in the same group:

- [The record meter](./account-record-meter.md) — The licence is on rows delivered, not on requests made. This is the most commonly misunderstood mechanic here, and it changes how you write your client.
- [Sign-in and the dashboard](./account-sign-in.md) — Passwordless sign-in, every control on the account page, and what rotating or cancelling a key actually does.
- [Billing, invoices and status](./account-billing.md) — What happens between clicking buy and the key switching on, where the invoice comes from, and how to tell whether the data behind the API is current.

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
