Salary Data API: Pay Ranges by Job Title & Level avatar

Salary Data API: Pay Ranges by Job Title & Level

Pricing

from $4.00 / 1,000 benchmarks

Go to Apify Store
Salary Data API: Pay Ranges by Job Title & Level

Salary Data API: Pay Ranges by Job Title & Level

Get salary benchmarks (p10-p90, annualised, with n) and pay ranges from 150,000+ employer-posted jobs across 11,000+ companies, updated daily. Filter by title, seniority, country and currency. No scraping at run time.

Pricing

from $4.00 / 1,000 benchmarks

Rating

0.0

(0)

Developer

Redomic

Redomic

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

an hour ago

Last modified

Features

Limited permissions

Share

Salary Data API: Pay Ranges by Job Title, Level and Location

What do US companies pay a mid-level software engineer right now? This Actor answers from the pay ranges employers publish in their own job ads: about 150,000 salary-bearing postings at more than 11,000 companies, refreshed every day. You get percentiles (p10 to p90) by job title, level and country, or the individual postings behind them, each with a link to the ad.

Who uses it

  • Recruiters and hiring managers checking an offer against what other companies advertise for the same role.
  • Compensation teams building or reviewing pay bands by level and location.
  • HR tech products and job sites that show salary estimates and want fresh numbers through an API.

What you get

A run on 15 November 2026 for software engineer in the United States returned these benchmarks (yearly pay, USD):

Level25th percentileMedian75th percentileJob adsCompanies
Intern$90,900$101,367$114,4005437
Junior$122,500$140,000$150,0008554
Mid$152,500$190,000$225,0002,418740
Senior$180,521$200,000$222,5002,229783
Lead/Principal$213,688$239,200$276,4981,504541
Manager$167,500$200,000$251,125119

Each benchmark row also carries p10 and p90, the currency, the data date, and up to five sample employers with links to their postings, so you can check where a number comes from.

Ask for the postings themselves and you get one row per job ad. Data engineer jobs in the US posted in the last two weeks, from the same day:

CompanyRoleLevelLocationPosted range (USD per year)Posted
TriumphData EngineerMidSan Francisco200,000 to 400,00013 Nov
SuperhumanData Engineer, FoundationsMidSan Francisco206,000 to 290,00013 Nov
Gatik AISenior Data EngineerSeniorSanta Clara, CA180,000 to 260,00013 Nov
WayveData Engineer, Security AnalyticsMidSunnyvale, CA186,100 to 243,30013 Nov
BlockStaff Data EngineerLead/PrincipalBay Area, CA239,600 to 359,40012 Nov

Where the numbers come from

Several US states, including California, New York, Colorado and Washington, require employers to post a pay range in job ads, and more EU countries are following. We collect the open jobs on more than 11,000 company career sites (Greenhouse, Lever and Ashby boards) every day and keep the ads that include a range.

Each ad counts once, at the midpoint of its range, converted to a yearly figure. A level with fewer than 5 ads or fewer than 5 different employers is left out, so you never quote a median that rests on one company.

Coverage is strongest in the US, and in tech hubs in particular. Europe and Canada have fewer ads with posted pay, so their benchmarks rest on smaller samples. Check the job ad count (n) and the company count (companies) before you quote a number.

Modes

ModeWhat you get
benchmark (default)Percentiles by title, level, country and currency. Set cells: true to split them by city as well. Set benchmarkByCompany: true to see one row per company.
jobsThe individual ads with posted range, yearly range, level, location, posting date and URL.
closedPay from ads that closed recently: the roles that were actually filled, not ads that stay up for months.

Price

$5 per 1,000 benchmark rows and $1 per 1,000 job rows. There's no start fee. The software engineer query above returned 6 benchmark rows and cost $0.03.

How to run it

Benchmarks for one role in one country:

{
"mode": "benchmark",
"jobTitles": ["product manager"],
"countries": ["United States"]
}

Fresh job ads in a pay band, for sourcing or a quick market check:

{
"mode": "jobs",
"jobTitles": ["data engineer"],
"countries": ["United States"],
"minSalaryAnnual": 150000,
"postedWithinDays": 14,
"maxItems": 100
}

What recently filled roles paid:

{
"mode": "closed",
"jobTitles": ["software engineer"],
"countries": ["United States"]
}

Ready-made searches, each with sample results on its own page:

Track pay over time

Set monitor: true and schedule the Actor daily. The first run returns everything as new. After that you get only rows that are new, changed (a pay range or level moved) or removed. You pay only for new and changed rows, so a quiet day costs nothing.

For benchmarks, output: "events" returns a row only when the 25th percentile, median or 75th percentile moves by more than changeBand (5% by default). Connect the run to Slack, email or Google Sheets through Apify integrations and you get an alert when the market moves.

Input

FieldDefaultWhat it does
modebenchmarkbenchmark, jobs or closed.
jobTitles["software engineer"]Matches whole words in the job title. Leave it empty to group benchmarks by role family instead.
roleFamiliesallFor example Engineering - Data, Product Management, Sales, Healthcare/Clinical.
seniorityallIntern, Junior, Mid, Senior, Lead/Principal, Manager, Director, Executive.
countriesallA name or ISO code: United States, US, Germany.
locationsallAny part of the location text: a city, state or region.
remoteOnlyfalseRemote jobs only.
companiesallCompany names or board tokens.
currencyas postedConvert to USD, EUR, GBP, CAD or AUD at the fixed rates below.
minSalaryAnnual, maxSalaryAnnualnoneKeep ads whose yearly range overlaps this band.
postedWithinDaysnoneKeep ads posted in the last N days.
minDaysOpen, maxDaysOpennoneKeep ads open at least or at most N days.
excludeEvergreenfalseDrop ads open for 180 days or more.
minSample5The fewest ads a benchmark needs before it's returned.
cellsfalseSplit benchmarks by city.
benchmarkByCompanyfalseIn benchmark mode, return one row per company with company, percentiles and n. Single-employer groups are allowed in this mode.
includeAggregatorsfalseInclude job boards that repost other companies' ads.
maxItems20The most rows to return.
monitor, stateKeyoffReturn only changes since the last run (see above).
output, changeBandrows, 0.05events returns only benchmark moves bigger than changeBand.

Output fields

Benchmark row: query, roleFamily, seniority, country, city (cells only), company (company benchmarks only), currency, period, p10, p25, p50, p75, p90, n, companies, sampleCompanies, sampleJobUrl1 to sampleJobUrl3, dataAsOf.

Job row: company, title, roleFamily, seniority, location, country, remote, salaryMin, salaryMax, salaryCurrency, salaryPeriod, salaryAnnualMin, salaryAnnualMax, url, postedAt, firstSeen, ageDays, daysOpen, dataAsOf.

Every column is flat, so the results open cleanly in Excel or Google Sheets.

Currency conversion

Leave currency empty to keep each ad's own currency. If you set one, the Actor converts with these fixed rates from 8 November 2026 (value of one unit in USD): EUR 1.08, GBP 1.29, CAD 0.73, AUD 0.65, CHF 1.13, SEK 0.096, NOK 0.094, DKK 0.145, PLN 0.26, INR 0.012, JPY 0.0064, SGD 0.78, NZD 0.60, HKD 0.128, BRL 0.19, MXN 0.055, ZAR 0.058, ILS 0.27.

FAQ

Is this survey data? No. Every number comes from a pay range an employer published in a job ad. Nobody self-reports anything.

Are posted ranges what people actually earn? They're what the employer advertised. Final offers can land anywhere in the range, and bonuses and equity usually aren't included.

Why is a level or city missing? It had fewer than 5 ads or fewer than 5 employers. Lower minSample if you want thinner samples, and check n and companies before you rely on them. With benchmarkByCompany: true, single-employer groups are returned when they meet minSample.

How do you compute the median? Each ad contributes the midpoint of its range, converted to a yearly amount (hourly × 2,080, daily × 260, weekly × 52, monthly × 12). Percentiles use linear interpolation over those midpoints.

How fresh is it? We collect the jobs every day. dataAsOf on each row tells you the date of the data behind it.

Can I use it from my own code? Yes. Call the Actor through the Apify API or a client library and read the dataset as JSON or CSV.

En español

Benchmarks salariales a partir de los rangos de pago que publican las empresas en sus ofertas: percentiles por puesto, nivel y país, o las ofertas individuales con su enlace. Datos actualizados cada día.

Auf Deutsch

Gehaltsdaten aus den Gehaltsspannen, die Arbeitgeber in ihren Stellenanzeigen veröffentlichen: Perzentile nach Jobtitel, Level und Land oder die einzelnen Anzeigen mit Link. Täglich aktualisiert.

Ready-made examples

Each one opens a saved run you can copy and start with one click.

Use it from AI agents (MCP) and Python

AI agents. Add this Actor as a tool in Claude, Cursor, VS Code or any MCP client through the Apify MCP server. The agent reads the input schema, so a plain request is enough.

{
"mcpServers": {
"salary-data": {
"url": "https://mcp.apify.com?tools=redomic/salary-data",
"headers": {
"Authorization": "Bearer <YOUR_APIFY_TOKEN>"
}
}
}
}

Python. pip install apify-client, then:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("redomic/salary-data").call(run_input={"mode": "benchmark", "jobTitles": ["software engineer"], "maxItems": 5})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)

More from us