endpoints
Key and metadata
Four endpoints that describe the API rather than return rows: your key, the filter vocabularies, the freshness report and the provider list.
1GET /v1/me
Your key, its plan, its limits and today's usage. Costs no records, so it is safe to poll and safe to call on start-up.
In depthWhy it exists, what it is not, what people get wrong
The first call to make with a new key, and the call to make when something is confusing. It answers “is this key alive”, “which plan is it on” and “how much have I used today” in one round trip, and it does not touch the record meter.
It reports request usage, not record usage — the record counters live in the X-RateLimit-Records-* response headers on any row-returning call. That split is worth remembering: this endpoint tells you about the throttle, the headers tell you about the licence.
Exact contractTypes, defaults, ranges, errors, edge cases
| Code | What it means |
|---|---|
200 | Key status. |
401 | Missing, unknown, revoked or expired key. All four are reported identically. |
429 | Over your plan's per-minute or per-day limit. Retry-After says how long. |
{
"created": "2026-08-22",
"key_prefix": "joadocs",
"plan": "signal",
"status": "active",
"limits": { "per_day": 400000, "per_minute": 300 },
"renews_or_expires": null,
"usage_today": 1
}key_prefix- A short, non-secret label for the key. Safe to log and to show a user; it is how you tell two of your own keys apart.
statusactiveis the usable state. A revoked or expired key does not reach this endpoint — it gets a 401.renews_or_expires- The next billing date on a subscription, or null on a plan that does not renew.
usage_today- Requests made today, against
limits.per_day. Resets at UTC midnight.
$ curl -s -H "Authorization: Bearer $JOA_KEY" https://api.jobopportunitiesapi.org/v1/me | jq { "created": "2026-08-22", "key_prefix": "joadocs", "plan": "signal", "status": "active", "limits": { "per_day": 400000, "per_minute": 300 }, "renews_or_expires": null, "usage_today": 1 }
2GET /v1/meta/facets
Every filter value with its live count. This is the list to enumerate at run time instead of hard-coding a vocabulary.
In depthWhy it exists, what it is not, what people get wrong
One response carries every controlled vocabulary the listing endpoints accept — categories, countries, cities, remote statuses, employment types, seniorities, source types and providers — each with the number of live rows behind it. It is the single most useful call for building a filter UI, and the correct defence against a value that has left the vocabulary.
Exact contractTypes, defaults, ranges, errors, edge cases
| Code | What it means |
|---|---|
200 | Facet counts. |
401 | Missing, unknown, revoked or expired key. All four are reported identically. |
429 | Over your plan's per-minute or per-day limit. Retry-After says how long. |
| Facet group | Filters | Note |
|---|---|---|
family | category, exclude_category | Named family in the facet response and category in the filter. |
country | country, exclude_country | ISO-3166 alpha-2. |
city | city | Resolved city names; thinner coverage than country. |
remote | remote | remote, hybrid, on_site, not_stated. |
employment | employment_type | Includes not_stated. |
seniority | seniority | Includes not_stated. |
source_type | source_type, exclude_source_type | aggregator and agency are reserved and match nothing. |
provider | provider, exclude_provider | Also available in richer form at /public/providers. |
| Value to send | Label | Live rows |
|---|---|---|
Engineering | Engineering | 434,035 |
Healthcare | Healthcare | 417,776 |
Operations & Admin | Operations & Admin | 370,013 |
Sales | Sales | 285,637 |
Skilled Technician | Skilled Technician | 220,289 |
Retail | Retail | 206,182 |
uncategorised | Uncategorised | 192,724 |
Hospitality | Hospitality | 187,079 |
Finance | Finance | 178,985 |
Logistics & Transport | Logistics & Transport | 108,760 |
Marketing | Marketing | 96,981 |
Customer Support | Customer Support | 95,756 |
Education | Education | 84,382 |
Manufacturing | Manufacturing | 83,836 |
HR & Recruiting | HR & Recruiting | 71,093 |
Data & Analytics | Data & Analytics | 65,005 |
Consulting & Strategy | Consulting & Strategy | 62,272 |
Construction & Trades | Construction & Trades | 51,899 |
Legal & Compliance | Legal & Compliance | 47,148 |
Product | Product | 37,156 |
Design | Design | 36,386 |
Security | Security | 30,377 |
Science & Research | Science & Research | 28,812 |
Procurement | Procurement | 19,981 |
Safety & Environment | Safety & Environment | 14,347 |
25 values, rendered from /public/facets (keyless) — the same data as /v1/meta/facets. Enumerate it at run time rather than hard-coding this list.
curl -s https://api.jobopportunitiesapi.org/public/facets \
| jq '{groups: (.data | keys), categories: (.data.family[:5])}'3GET /v1/meta/freshness
How recently the ledger was verified, how much of it carries each field, and how many roles closed in the last day and week.
In depthWhy it exists, what it is not, what people get wrong
Use this to decide whether the data behind an answer is current enough for what you are doing with it, and to show a “last updated” line honestly. It also carries the indicative currency rates used to compute salary_min_annual_eur.
For the broader picture — the three populations, the reconciliation, the excluded sources — use /public/coverage instead. This endpoint is about time; that one is about composition.
Exact contractTypes, defaults, ranges, errors, edge cases
| Figure | Value | Meaning |
|---|---|---|
measured_at | 12 September 2026, 01:52 UTC | When the snapshot behind this report was taken. |
generated_at | 12 September 2026, 02:25 UTC | When this response was assembled. |
live_listings | 3,426,911 | Rows /v1/jobs will serve. |
ledger_rows | 9,357,945 | Live + withheld + closed. |
closures.last_24h | 42,113 | Roles that left their source in the last day. |
closures.last_7d | 1,640,300 | …and in the last week. |
closures.total | 5,707,085 | Retained: kept indefinitely. |
Measured 12 September 2026, 01:52 UTC · rendered from /public/freshness, which needs no key. These figures move; the endpoint is always right and this page is only as fresh as its last build.
| Code | What it means |
|---|---|
200 | Freshness and coverage report. |
401 | Missing, unknown, revoked or expired key. All four are reported identically. |
429 | Over your plan's per-minute or per-day limit. Retry-After says how long. |
4GET /v1/meta/providers
Every source the ledger is built from, with its live row count and its description coverage.
In depthWhy it exists, what it is not, what people get wrong
The provider list is both a vocabulary and a data-quality report. Description coverage varies from around 60% to nearly 100% depending on which system published the row, so if your product needs advert bodies, this table tells you which providers to prefer.
Exact contractTypes, defaults, ranges, errors, edge cases
| provider | Label | Live rows | With a description | source_class | source_type |
|---|---|---|---|---|---|
company_site | Company career site | 1,895,315 | 1,590,079 (83.8%) | direct | career_site |
workday | Workday | 635,841 | 275,365 (43.3%) | employer_ats | ats |
oracle | Oracle HCM | 235,520 | 203,871 (86.5%) | employer_ats | ats |
greenhouse | Greenhouse | 159,168 | 159,150 (99.9%) | employer_ats | ats |
smartrecruiters | SmartRecruiters | 102,021 | 100,895 (98.8%) | employer_ats | ats |
paylocity | Paylocity | 85,394 | 80,054 (93.7%) | employer_ats | ats |
teamtailor | Teamtailor | 69,887 | 69,825 (99.9%) | employer_ats | ats |
ashby | Ashby | 68,652 | 68,652 (100%) | employer_ats | ats |
workable | Workable | 63,320 | 63,318 (99.9%) | employer_ats | ats |
lever | Lever | 49,924 | 49,203 (98.5%) | employer_ats | ats |
personio | Personio | 48,414 | 44,066 (91%) | employer_ats | ats |
recruitee | Recruitee | 35,912 | 35,892 (99.9%) | employer_ats | ats |
breezy | Breezy HR | 35,180 | 34,495 (98%) | employer_ats | ats |
bamboohr | BambooHR | 25,628 | 25,036 (97.6%) | employer_ats | ats |
join | join.com | 16,403 | 16,368 (99.7%) | employer_ats | ats |
rippling | Rippling | 16,063 | 15,721 (97.8%) | employer_ats | ats |
pinpoint | Pinpoint | 14,627 | 14,627 (100%) | employer_ats | ats |
ukg | UKG Pro | 11,309 | 11,309 (100%) | employer_ats | ats |
jobtech_sweden | JobTech Sweden | 10,235 | 10,235 (100%) | government | public_agency |
af_employer_direct | Employer career site (Sweden) | 887 | 885 (99.7%) | direct | career_site |
nav_norway | NAV Norge | 144 | 0 (0%) | government | public_agency |
extension_submission | Direct submission | 6 | 5 (83.3%) | direct | career_site |
22 providers. This list is the vocabulary the provider and exclude_provider filters accept: a name that is not here is a 422, never a silently empty page. Rendered from /public/providers. Read it at request time rather than pinning this list — on 2026-08-15 three names left it and a documented example became a 422 the next morning.
| Code | What it means |
|---|---|
200 | The provider list. |
401 | Missing, unknown, revoked or expired key. All four are reported identically. |
429 | Over your plan's per-minute or per-day limit. Retry-After says how long. |
The keyless mirror is /public/providers, with the same shape. Both list only redistributable providers — the sources we fetch and do not republish are named separately, under excluded_sources on /public/coverage. See Sourcing and refusals.
This page was rendered 12 September 2026, 02:25 UTC. Every figure on it comes from the endpoint named beside it, and every published request is re-sent against the live API before this site is allowed to build. If something here is wrong, the thumbs-down above reaches a person.