USAJobs Historical API Data

Data collection last run: 2025-07-08

⚠️ This is not an official USAJobs project

Resources

Dataset: 2,975,686 total job postings | Coverage: | Source: USAJobs Historical + Current APIs with field rationalization and deduplication

Table of Contents

Data Coverage by Year

Year Jobs Opened Jobs Closed Coverage Notes
201350Very limited
20142419Very limited
2015140131Very limited
20163,8791,633Very limited
2017237,145226,248✅ Complete year
2018328,111315,729✅ Complete year
2019349,256336,608✅ Complete year
2020327,545315,161✅ Complete year
2021369,151352,375✅ Complete year
2022441,604419,295✅ Complete year
2023454,652434,527✅ Complete year
2024367,744352,296✅ Complete year
202596,43095,337Current through July 08, 2025

All Fields

Note: This table shows fields from historical jobs data. Current jobs API contains additional fields that are preserved in the original nested structure but not included in this rationalized view.

Field Type Examples Completeness
HiringPaths JSON Array [{"hiringPath": "Custom announcement"}], [{"hiringPath": "The public"}] (75896 unique combinations) 100%
JobCategories JSON Array [{"series": "1320"}, {"series": "1310"}, {"series": "1301"}, {"series": "0801"}], [{"series": "0401"}, {"series": "1301"}, {"series": "0801"}, {"series": "0819"}, {"series": "0020"}], [{"series": "5767"}], [{"series": "1350"}, {"series": "0850"}, {"series": "0810"}, {"series": "0808"}, {"series": "0830"}] (3060 unique) 100%
PositionLocations JSON Array [{"positionLocationCity": "Urbana", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Falls Church", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Woodlawn", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Baltimore", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Durham", "positionLocationState": "North Carolina", "positionLocationCountry": "United States"}, {"positionLocationCity": "Washington", "positionLocationState": "District of Columbia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Alexandria", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Springfield", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Arlington", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}], [{"positionLocationCity": "China Lake", "positionLocationState": "California", "positionLocationCountry": "United States"}] (26311 unique combinations) 100%
agencyLevel Integer 1, 2 100%
agencyLevelSort String Department of Justice\Offices, Boards and Divisions, Department of Education\Office of the General Counsel, Department of the Air Force\Air Force Medical Command, Department of Labor\Office of Federal Contract Compliance Programs (542 unique) 100%
announcementClosingTypeCode String 01, 03, 02 100%
announcementClosingTypeDescription String Closing Date, Applicant Cut-Off, Open Continuous 100%
announcementNumber String MCFS249766104342, DECA-24-12348385-MP, MCGK247968088011, NV-Merit-25-12572459-JP (363801 unique) 100%
appointmentType String Recent graduates, Temporary Promotion, Multiple, Intermittent (15 unique) 100%
disableApplyOnline String N, Y 100%
drugTestRequired String N 100%
hiringAgencyCode String ARAE, VAPA, TN00, HE33 (528 unique) 100%
hiringAgencyName String Office of the Assistant Secretary for Public and Intergovernmental Affairs, Cybersecurity and Infrastructure Security Agency, United States Army Futures Command, Office of Federal Contract Compliance Programs (502 unique) 99%
hiringDepartmentCode String NM, FT, MI, FL (122 unique) 100%
hiringDepartmentName String Department of Labor, Other Agencies and Independent Organizations, Department of Commerce, Department of State (26 unique) 100%
hiringSubelementName String National Institute on Disability, Independent Living, and Rehabilitation Research (NIDILRR), TF VIPR Contracting Division, TF VIPR Execution Branch, Omaha District - Omaha Safety and Occupational Health Office, Orlando VA Healthcare System (59973 unique) 62%
inserted_at String 2025-07-05T15:37:35.666806, 2025-07-05T14:04:05.156353, 2025-07-05T14:29:28.730118, 2025-07-05T15:31:46.130319 (367177 unique) 100%
maximumGrade String 2, 35, G, 60 (127 unique) 100%
maximumSalary Number $0, $105,612, $470,281 (range: $0-$470,281) (15671 unique) 100%
minimumGrade String KH, B, 18, EI (125 unique) 100%
minimumSalary Number $0, $72,553, $400,000 (range: $0-$400,000) (15409 unique) 100%
payScale String IS, DX, KI, NY (191 unique) 100%
positionCloseDate String 2025-06-21, 2025-11-03, 2025-11-24, 2024-07-24 (672 unique) 100%
positionExpireDate String 2024-11-07, 2025-02-17, 2024-01-21, 2025-05-05 (550 unique) 9%
positionOpenDate String 2024-01-12, 2024-01-13, 2024-08-28, 2024-07-10 (365 unique) 100%
positionOpeningStatus String Applications under review, Job closed, Job canceled, Candidate selected (5 unique) 100%
positionTitle String Physician Assistant (Surgical Service- Gynecology), Attorney (Senior CLC Attorney), Senior Anti-Money Laundering Examiner, CG-0570-14, Chief Resident Services (77986 unique) 100%
promotionPotential String 72, 41, FPMC, NO (115 unique) 100%
relocationExpensesReimbursed String N 100%
salaryType String Per Year, Per Hour, Without Compensation, Per Day (9 unique) 100%
securityClearance String Not Required, Secret, Other, L Access Authorization (8 unique) 100%
securityClearanceRequired String N, Y 100%
serviceType String Competitive, Excepted, Senior Executive 100%
supervisoryStatus String N, Y 100%
teleworkEligible String N 100%
totalOpenings String 165, 38, 55, 100 (157 unique) 90%
travelRequirement String Not required, Occasional travel, 25% or less, 75% or less (6 unique) 100%
usajobsControlNumber Integer 593449300, 693894500, 702096500 (367177 unique) 100%
usajobs_control_number String 593449300, 693894500, 702096500 (367177 unique) 100%
vendor String USASTAFFING, Monster - Hiring Management, FAA - SWIFT, HQMC MCCS (PeopleSoft) (8 unique) 100%
whoMayApply String Status Candidates (Merit Promotion and VEOA Eligibles) 0%
workSchedule String Full-time, Intermittent, Part-time, Multiple Schedules (6 unique) 100%

API Field Mapping & Normalization

This dataset combines data from two USAJobs APIs with field rationalization for consistent querying:

API Sources

Note: There is overlap between the APIs (2024-2025 jobs appear in both), but we collect from both APIs for completeness.

Normalized Fields

Historical Field Name Historical API Source Current API Source Notes
usajobsControlNumber usajobsControlNumber Extracted from PositionURI Numeric job identifier
announcementNumber announcementNumber PositionID Public announcement ID
hiringAgencyName hiringAgencyName DepartmentName Agency name
hiringAgencyCode hiringAgencyCode OrganizationCodes (first part) Agency code
positionTitle positionTitle PositionTitle Job title
minimumGrade minimumGrade JobGrade[0].Code Minimum grade level
maximumGrade maximumGrade JobGrade[-1].Code Maximum grade level
minimumSalary minimumSalary PositionRemuneration[0].MinimumRange Minimum salary
maximumSalary maximumSalary PositionRemuneration[0].MaximumRange Maximum salary
positionOpenDate positionOpenDate PositionStartDate Position open date
positionCloseDate positionCloseDate PositionEndDate Position close date

Data Processing Approach

Data Structure

Code Examples from examples.py

The examples.py script demonstrates both local file access and direct GitHub downloads. It runs complete analysis on 2.97M job postings and automatically cleans up downloaded files.

Local Data Loading

import pandas as pd

# Load a single year
df_2024 = pd.read_parquet('data/historical_jobs_2024.parquet')
print(f"✓ Successfully loaded {len(df_2024):,} job postings from 2024")

GitHub Download Example

import pandas as pd
import requests

# Download directly from GitHub
url = 'https://github.com/abigailhaddad/usajobs_historical/raw/main/data/historical_jobs_2024.parquet'
df = pd.read_parquet(url)
print(f"✓ Downloaded {len(df):,} job postings")
Output:
✓ Successfully loaded 367,177 job postings from 2024
  Columns: 42
  Memory usage: 952.5 MB

Top Hiring Agencies Analysis

# 1. TOP 15 HIRING AGENCIES (2024 DATA)
top_agencies = df_2024['hiringAgencyName'].value_counts().head(15)
for i, (agency, count) in enumerate(top_agencies.items(), 1):
    percentage = count / len(df_2024) * 100
    print(f"{i:2d}. {agency}: {count:,} jobs ({percentage:.1f}%)")
Output:
1. Veterans Health Administration: 59,233 jobs (16.1%)
2. Army National Guard Units: 10,323 jobs (2.8%)
3. Commander, Navy Installations: 9,198 jobs (2.5%)
4. U.S. Army Corps of Engineers: 9,048 jobs (2.5%)
5. Military Treatment Facilities under DHA: 8,859 jobs (2.4%)
6. Army Installation Management Command: 8,526 jobs (2.3%)
7. U.S. Marine Corps: 7,971 jobs (2.2%)
8. Internal Revenue Service: 7,955 jobs (2.2%)
9. Justice, Bureau of Prisons/Federal Prison System: 6,993 jobs (1.9%)
10. National Park Service: 5,527 jobs (1.5%)

Salary Analysis

# Salary statistics
records_with_salary = df_2024[df_2024['maximumSalary'].notna()]
print(f"Records with salary data: {len(records_with_salary):,} ({len(records_with_salary)/len(df_2024)*100:.1f}%)")

# Salary ranges
min_range = f"${records_with_salary['minimumSalary'].min():,.0f} - ${records_with_salary['minimumSalary'].max():,.0f}"
max_range = f"${records_with_salary['maximumSalary'].min():,.0f} - ${records_with_salary['maximumSalary'].max():,.0f}"
median_range = f"${records_with_salary['minimumSalary'].median():,.0f} - ${records_with_salary['maximumSalary'].median():,.0f}"

print(f"Minimum salary range: {min_range}")
print(f"Maximum salary range: {max_range}")  
print(f"Median salary range: {median_range}")
Output:
Records with salary data: 367,177 (100.0%)
Minimum salary range: $0 - $400,000
Maximum salary range: $0 - $470,281
Median salary range: $72,553 - $105,612

Multi-Year Analysis with DuckDB

import duckdb

# Create DuckDB connection and register multiple Parquet files
conn = duckdb.connect('download/usajobs.duckdb')

# Register Parquet files as external tables
years = ['2022', '2023', '2024']
for year in years:
    file_path = f'data/historical_jobs_{year}.parquet'
    conn.execute(f"CREATE OR REPLACE VIEW jobs_{year} AS SELECT * FROM '{file_path}'")

# Create unified view
conn.execute("""
    CREATE OR REPLACE VIEW all_jobs AS 
    SELECT * FROM jobs_2024 
    UNION ALL SELECT * FROM jobs_2023 
    UNION ALL SELECT * FROM jobs_2022
""")

# Query salary trends by year
salary_trends = conn.execute("""
    SELECT 
        EXTRACT(year FROM positionOpenDate) as year,
        ROUND(AVG(minimumSalary)) as avg_min,
        ROUND(AVG(maximumSalary)) as avg_max,
        ROUND(percentile_cont(0.5) WITHIN GROUP (ORDER BY minimumSalary)) as median_min,
        ROUND(percentile_cont(0.5) WITHIN GROUP (ORDER BY maximumSalary)) as median_max,
        COUNT(*) as jobs
    FROM all_jobs 
    WHERE minimumSalary IS NOT NULL 
    GROUP BY EXTRACT(year FROM positionOpenDate)
    ORDER BY year DESC
""").fetchdf()

print(salary_trends)
Output:
Year | Avg Min | Avg Max | Median Min | Median Max | Jobs
-----|---------|---------|------------|------------|-----
2024 | $ 74222 | $104262 | $ 72553 | $ 105612 | 366772
2023 | $ 69048 | $ 97341 | $ 69107 | $ 93591 | 454348
2022 | $ 64748 | $ 91485 | $ 62926 | $ 88792 | 441351

Monthly Hiring Patterns

# Monthly posting patterns
monthly_posts = df_2024.groupby(df_2024['positionOpenDate'].dt.month).size()
print("Monthly posting patterns:")
month_names = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
for month, count in monthly_posts.items():
    percentage = count / len(df_2024) * 100
    print(f"    {month_names[month-1]}: {count:,} jobs ({percentage:.1f}%)")
Output:
Monthly posting patterns:
    Jan: 35,939 jobs (9.8%)
    Feb: 34,076 jobs (9.3%)
    Mar: 32,177 jobs (8.8%)
    Apr: 30,956 jobs (8.4%)
    May: 29,006 jobs (7.9%)
    Jun: 25,996 jobs (7.1%)
    Jul: 29,831 jobs (8.1%)
    Aug: 31,476 jobs (8.6%)
    Sep: 28,414 jobs (7.7%)
    Oct: 31,775 jobs (8.7%)
    Nov: 28,604 jobs (7.8%)
    Dec: 28,927 jobs (7.9%)

Most Common Position Titles

# Most common position titles
common_titles = df_2024['positionTitle'].value_counts().head(10)
print("Most common position titles:")
for i, (title, count) in enumerate(common_titles.items(), 1):
    percentage = count / len(df_2024) * 100
    print(f"   {i:2d}. {title}: {count:,} ({percentage:.1f}%)")
Output:
Most common position titles:
    1. Program Analyst: 3,324 (0.9%)
    2. Management and Program Analyst: 2,628 (0.7%)
    3. PROGRAM ANALYST: 2,203 (0.6%)
    4. Budget Analyst: 2,008 (0.5%)
    5. Administrative Officer: 1,817 (0.5%)
    6. Management Analyst: 1,606 (0.4%)
    7. Contract Specialist: 1,569 (0.4%)
    8. Logistics Management Specialist: 1,424 (0.4%)
    9. FINANCIAL MANAGEMENT ANALYST: 1,207 (0.3%)
    10. LOGISTICS MANAGEMENT SPECIALIST: 1,129 (0.3%)
Access: Download Parquet files from /data/ directory | Full examples: Run examples.py for complete analysis patterns | Source: Data collected from USAJobs.gov APIs