Free financial calculators. No signup. 100% private. Data sourced from IRS.gov and BLS.gov.

Home › Salary API

PayCrunch Salary API — free, public, static JSON

Free · No key · CC BY 4.0

Annual pay for 1,008 U.S. job titles and the best-paying state for 824 occupations, served as flat JSON files. There is no server, no account, no key and no rate limit: paycrunch.co is a static site, and every endpoint below is a file.

762 of the 1,008 job records carry Bureau of Labor Statistics OEWS figures published under a named SOC code. The remaining 246 cover job titles BLS does not track separately; those records are labelled a PayCrunch estimate and carry a disclaimer field. Nothing in this API mixes the two — see telling the two apart.

GET https://paycrunch.co/api/v1/index.json
No API key
No rate limit
CORS enabled
CC BY 4.0

Quick start

curl

curl -s https://paycrunch.co/api/v1/jobs/registered-nurse-salary.json | jq '{name, median: .wage.median, top: .ceiling.amount, state: .ceiling.state}' { "name": "Registered Nurse", "median": 97550, "top": 213320, "state": "California" }

fetch()

const res = await fetch('https://paycrunch.co/api/v1/jobs/registered-nurse-salary.json'); const job = await res.json(); console.log(job.name, job.wage.median, job.ceiling.amount, job.ceiling.state); // Registered Nurse 97550 213320 California // Never print an estimate as a BLS figure. if (job.estimated) console.warn(job.source_release, '-', job.disclaimer);

Slugs come from /api/v1/jobs.json and are the same slugs the site uses, so registered-nurse-salary is both /api/v1/jobs/registered-nurse-salary.json and /jobs/registered-nurse-salary.html.

Endpoints

Base URL https://paycrunch.co/api/v1. Everything is GET, everything returns application/json; charset=utf-8. 1,461 files in total.

EndpointReturnsRecords
/api/v1/index.jsonAPI metadata, counts, licence, citation string, links to every endpoint1
/api/v1/jobs.jsonCompact list of every job. The discovery endpoint1,008
/api/v1/jobs/{slug}.jsonOne job in full: every percentile, the ceiling and its basis, the step-up role1,008
/api/v1/soc/{code}.jsonLookup by SOC code, for anyone arriving from BLS data449
/api/v1/state-wages.jsonMedian and 90th-percentile wage by state for every occupation BLS reports at the 500-employee floor. Also embedded in each /soc/ record11,548
/api/v1/states.jsonBest-paying state per occupation, with the unfiltered comparison824

There is a machine-readable description of all of this at /openapi.json (OpenAPI 3.1), if you would rather generate a client than read a table.

index.json

Start here if you are exploring. It states the record counts, the licence, the citation string and the URL of every other endpoint, so a client can discover the rest of the API from one request.

GET https://paycrunch.co/api/v1/index.json
{ "name": "PayCrunch Salary API", "version": "v1", "description": "Free, public, read-only annual pay data for 1,008 occupations in the United States: entry, median and top of the published range, plus the best-paying state by occupation. Static JSON. No key, no rate limit.", "base_url": "https://paycrunch.co/api/v1", "documentation": "https://paycrunch.co/api.html", "authentication": "none", "rate_limit": "none", "last_updated": "2026-08-31", "license": { "id": "CC-BY-4.0", "name": "Creative Commons Attribution 4.0 International", "url": "https://creativecommons.org/licenses/by/4.0/" }, "citation": "PayCrunch Salary API, https://paycrunch.co/api.html (wage data: U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics, May 2025). Accessed 2026-08-31.", "counts": { "jobs": 1008, "jobs_bls": 762, "jobs_estimated": 246, "soc_codes": 449, "state_records": 824, "files": 1461 } }

Trimmed: the live file also carries sources, tiers, attribution and the full endpoints array.

jobs.json

Every job in one file, one row each. Kept to the fields you need to search, sort and link: slug, name, SOC code, median, ceiling, ceiling state, and the provenance block. Fetch the per-job file when you need percentiles.

GET https://paycrunch.co/api/v1/jobs.json
{ "endpoint": "jobs", "count": 1008, "last_updated": "2026-08-31", "license": "CC-BY-4.0", "jobs": [ { "slug": "registered-nurse-salary", "name": "Registered Nurse", "soc": "29-1141", "tier": "A", "estimated": false, "median": 97550, "ceiling": 213320, "ceiling_state": "California", "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/registered-nurse-salary.html" }, { "slug": "actor-salary", "name": "Actor", "soc": null, "tier": "B", "estimated": true, "median": 52000, "ceiling": 162000, "ceiling_state": null, "source": "PayCrunch", "source_release": "PayCrunch estimate", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/actor-salary.html" } ] }

Trimmed to two rows of 1,008 — one BLS-sourced, one estimate — and the file’s field_notes block is omitted.

FieldMeaning
slugStable identifier. Use for /api/v1/jobs/<slug>.json and /jobs/<slug>.html.
socStandard Occupational Classification code. null on estimates, so an estimate cannot be joined into BLS data by SOC.
tier"A" BLS figures under a named SOC code. "B" PayCrunch estimate.
estimatedBoolean. The one field to branch on.
medianAnnual USD, 50th percentile of the wage distribution.
ceilingAnnual USD, top of the published range.
ceiling_stateThe state that ceiling comes from, or null where the figure is national.
source_release"BLS OEWS May 2025" or "PayCrunch estimate".
urlThe human page for this record.

jobs/{slug}.json

The full record: identity, all five wage percentiles, the ceiling with the basis it was computed from, and the step-up role — the job people in this one most often move up into, with that occupation’s own figures.

GET https://paycrunch.co/api/v1/jobs/registered-nurse-salary.json
{ "slug": "registered-nurse-salary", "name": "Registered Nurse", "tier": "A", "estimated": false, "soc": "29-1141", "bls_title": "Registered Nurses", "job_zone": 4, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/registered-nurse-salary.html", "wage": { "currency": "USD", "period": "year", "p10": 68940, "p25": 80330, "median": 97550, "p75": 112350, "p90": 137470, "source_release": "BLS OEWS May 2025" }, "ceiling": { "amount": 213320, "state": "California", "scope": "state", "estimated": false, "basis": "BLS OEWS May 2025 highest state-level top-of-range wage among states with at least 500 people in the job", "state_median": 140270, "state_employment": 338940 }, "step_up": { "title": "Nurse Practitioners", "soc": "29-1171", "median": 132300, "ceiling": { "amount": 240830, "state": "California", "scope": "state", "state_median": 168520, "state_employment": 25120 }, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "note": "The role people in this job most often move up into. Figures are BLS OEWS May 2025 for that occupation." } }

Trimmed: the live file also carries tier_note, core_tasks, hot_tech, license and attribution.

What the ceiling is

ceiling.amount is the highest state-level 90th-percentile annual wage BLS publishes for the occupation, restricted to states with at least 500 people employed in it. That floor exists because unfiltered state figures produce artefacts. Where no state clears the floor, the national 90th percentile is used and ceiling.scope is "national". ceiling.basis always spells out which of the two you are looking at.

Telling a BLS figure from an estimate

This is the part worth reading before you display anything. 762 job records carry real BLS OEWS figures. 246 cover job titles BLS does not publish separate wage data for, and their figures are a PayCrunch estimate derived from the closest occupation BLS does track.

Branch on estimated. Every record in every endpoint carries estimated (boolean), tier, source and source_release. Estimates additionally set soc to null, expose the nearest occupation as nearest_soc and nearest_bls_title instead, and carry a disclaimer string. Please do not present an estimate as a Bureau of Labor Statistics figure.
GET https://paycrunch.co/api/v1/jobs/actor-salary.json
{ "slug": "actor-salary", "name": "Actor", "tier": "B", "estimated": true, "soc": null, "nearest_soc": "27-2011", "nearest_bls_title": "Actors", "source": "PayCrunch", "source_release": "PayCrunch estimate", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/actor-salary.html", "wage": { "currency": "USD", "period": "year", "p10": 20000, "p25": null, "median": 52000, "p75": null, "p90": 120000, "source_release": "PayCrunch estimate" }, "ceiling": { "amount": 162000, "state": null, "scope": null, "estimated": true, "basis": "PayCrunch estimate - derived from the closest occupation BLS tracks (Actors, 27-2011)", "state_median": null, "state_employment": null }, "disclaimer": "This is a PayCrunch estimate, not a BLS figure. BLS does not publish separate wage data for this job title, so the figures were derived from the closest occupation BLS tracks. Do not cite them as Bureau of Labor Statistics data." }

Trimmed: the live file also carries tier_note, job_zone, step_up, core_tasks, hot_tech, license and attribution.

soc/{code}.json

Keyed by Standard Occupational Classification code, so if you already hold BLS data you can join on it directly. Each file gives the occupation’s figures once, then lists the PayCrunch pages that sit under it. Estimate pages that merely name this SOC as their nearest occupation are kept in a separate estimated_pages array and never mixed into jobs.

GET https://paycrunch.co/api/v1/soc/29-1141.json
{ "soc": "29-1141", "bls_title": "Registered Nurses", "bls_figures_available": true, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/cardiac-nurse-salary.html", "wage": { "currency": "USD", "period": "year", "p10": 68940, "p25": 80330, "median": 97550, "p75": 112350, "p90": 137470, "source_release": "BLS OEWS May 2025" }, "ceiling": { "amount": 213320, "state": "California", "scope": "state", "estimated": false, "basis": "BLS OEWS May 2025 highest state-level top-of-range wage among states with at least 500 people in the job", "state_median": 140270, "state_employment": 338940 }, "jobs": [ { "slug": "cardiac-nurse-salary", "name": "Cardiac Nurse", "median": 97550, "ceiling": 213320, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/cardiac-nurse-salary.html" } ], "estimated_pages": [ { "slug": "nurse-case-manager-salary", "name": "Nurse Case Manager", "median": 82000, "ceiling": 170690, "source": "PayCrunch", "source_release": "PayCrunch estimate", "last_updated": "2026-08-31", "url": "https://paycrunch.co/jobs/nurse-case-manager-salary.html", "disclaimer": "This is a PayCrunch estimate, not a BLS figure. BLS does not publish separate wage data for this job title, so the figures were derived from the closest occupation BLS tracks. Do not cite them as Bureau of Labor Statistics data." } ] }

Trimmed to one entry in each array — the live file lists 18 job pages and 2 estimate pages, and also carries best_paying_state, license and attribution.

Where PayCrunch has no BLS-sourced page under a SOC code, bls_figures_available is false, wage and ceiling are null, and a note says so.

states.json

The best-paying state for each of 824 occupations. BLS publishes a state figure regardless of how few people were surveyed there, so this dataset requires a state to employ at least 500 people in an occupation before its figure can be quoted. Each record also carries the unfiltered answer, so you can see where the floor changes it: filter_changed_answer.

GET https://paycrunch.co/api/v1/states.json
{ "endpoint": "states", "count": 824, "employment_floor": 500, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "license": "CC-BY-4.0", "records": [ { "soc": "29-1141", "occupation": "Registered Nurses", "national_entry": 68940, "national_median": 97550, "national_top": 137470, "best_state": "California", "best_state_top": 213320, "best_state_median": 140270, "best_state_employment": 338940, "scope": "state", "unfiltered_state": "California", "unfiltered_top": 213320, "unfiltered_employment": 338940, "filter_changed_answer": false, "source": "U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics", "source_release": "BLS OEWS May 2025", "last_updated": "2026-08-31", "url": "https://paycrunch.co/best-paying-states.html" } ] }

Trimmed to one record of 824; the file’s method, attribution and source_url fields are omitted here.

The same data as CSV, and the write-up of what the floor changes, are on .

Licence and attribution

The API is published under Creative Commons Attribution 4.0 International (CC BY 4.0). You may use it commercially, redistribute it and build on it, including in closed-source products. The one condition is credit.

Attribution

A link back to paycrunch.co in your UI, docs or about page is enough. Every response also carries an attribution string you can render verbatim:

PayCrunch (https://paycrunch.co), CC BY 4.0. Figures marked "BLS OEWS May 2025" come from the U.S. Bureau of Labor Statistics Occupational Employment and Wage Statistics, May 2025 release. Figures marked "PayCrunch estimate" are not BLS figures.

Citation

PayCrunch Salary API, https://paycrunch.co/api.html (wage data: U.S. Bureau of Labor Statistics, Occupational Employment and Wage Statistics, May 2025). Accessed 2026-08-31.

Underlying wage data is from the U.S. Bureau of Labor Statistics Occupational Employment and Wage Statistics, May 2025 release, which is a public-domain U.S. Government work. PayCrunch is not affiliated with, and this API is not endorsed by, the Bureau of Labor Statistics.

Practical notes

CORS

Browser fetch() works from any origin. paycrunch.co is served by GitHub Pages, which returns Access-Control-Allow-Origin: * on static files; this was checked against a live JSON file on this domain on 2026-08-31, and you can check it yourself:

curl -sI -H 'Origin: https://example.com' https://paycrunch.co/api/v1/index.json | grep -i access-control access-control-allow-origin: *

No key, no limit, no quota

There is nothing to sign up for and nothing to throttle, because there is no application here — just files on a CDN. Be reasonable: if you need every job record, fetch jobs.json once rather than 1,008 files, and cache what you pull.

Caching and freshness

Responses carry an ETag and a Last-Modified header, so conditional requests work. Every record carries last_updated, and index.json carries the record counts — poll that one small file to detect a rebuild rather than diffing the whole set.

Stability

The API is versioned in the path. Endpoints under /api/v1/ keep their shape: fields may be added, but existing fields will not be renamed or repurposed. A breaking change becomes /api/v2/.

Wage figures are distributions, not people

wage.p90 is the 90th percentile of the wage distribution for an occupation — the annual figure that nine tenths of published wages for that job fall below. It is a property of the pay range, not a rank for any individual.

Frequently asked questions

Do I need an API key?
No. These are static files. There is no key, no header and no account.
Is there a rate limit?
No rate limit is applied. Fetch jobs.json once instead of walking 1,008 individual files, and cache what you take.
Can I use it commercially?
Yes. CC BY 4.0 permits commercial use and redistribution. Credit PayCrunch with a link.
How often does the data change?
Wage figures follow the BLS OEWS release cycle, which publishes annually. The current release is May 2025. Each record carries last_updated.
How do I avoid quoting an estimate as a BLS figure?
Check estimated. Where it is true, source_release reads "PayCrunch estimate", soc is null, and the record carries a disclaimer string written for display.
Can I search or filter server-side?
No. There is no query layer. Fetch jobs.json (1,008 rows) and filter client-side, or index it into whatever you already run.
Something looks wrong. Who do I tell?
Use the contact page. Include the endpoint URL and the field.
IRS.gov data
BLS.gov verified
All 50 states
No signup required
Career Intelligence
Get the AI briefing for your career.

Free. No spam. We never sell your email.

paycrunch.co · About · Contact · Privacy · Terms · All Calculators