Article type: How-to guide. You already know USAJOBS and the occupational series you care about. This guide gets you one CSV each Monday of every public job in those series that closes in the next 7 days.
Prerequisites: Python 3.9+, requests, a free USAJOBS API key (developer.usajobs.gov) and the email you registered it with.
Tested on: 2 November 2026, against the live API.

Career counselors, veterans' transition offices and university career centers often get the same question: "What can I still apply for this week?" The USAJOBS website answers it one search at a time. The API answers it in one run, once you deal with three things:

  1. The default sort isn't by close date, so "first page" doesn't mean "closing soonest".
  2. ApplicationCloseDate has no time zone (2026-11-02T23:59:59.9970), but USAJOBS closes announcements at 11:59 p.m. Eastern Time on the closing date (USAJOBS Help Center).
  3. Some jobs close before that date. Agencies can close or remove an announcement early. "Applicant cut-off" jobs usually close at 11:59 p.m. ET on the day they reach a set number of applications.

The urgency is real. On 2 November 2026, 211 of the 325 announcements USAJOBS listed as open to the public in series 0343 (Management and Program Analysis) and 0201 (Human Resources Management) closed within 7 days, and 70 of those closed that same day. Half of all these announcements are open for 10 days or less.

Step 1: Put your key in environment variables

export USAJOBS_KEY="your-key" export USAJOBS_EMAIL="the-email-you-registered@example.com" 

USAJOBS wants the email as the User-Agent header and the key as Authorization-Key.

Step 2: Sort by close date and stop at the end of the window

Ask for SortField=closedate with SortDirection=Asc. The results then come back soonest-closing first, so you can stop paging at the first job that closes after your window instead of downloading the whole series.

Read the close date as Eastern time. A Monday-morning run from a server in any time zone then still counts a job that closes at 11:59 p.m. ET that night.

Save this as closing_soon.py:

import csv, os, time, requests from datetime import datetime, timedelta from zoneinfo import ZoneInfo SERIES = ["0343", "0201"] # Management and Program Analysis, Human Resources Management DAYS = 7 ET = ZoneInfo("America/New_York") HEADERS = { "Host": "data.usajobs.gov", "User-Agent": os.environ["USAJOBS_EMAIL"], "Authorization-Key": os.environ["USAJOBS_KEY"], } now = datetime.now(ET) cutoff = now + timedelta(days=DAYS) def closes_at(job): # "2026-11-02T23:59:59.9970", no zone: USAJOBS closes jobs at 11:59 pm Eastern  return datetime.fromisoformat(job["ApplicationCloseDate"][:19]).replace(tzinfo=ET) rows = {} # keyed by job ID: one job can list several series for series in SERIES: page = 1 while True: r = requests.get("https://data.usajobs.gov/api/Search", headers=HEADERS, timeout=60, params={ "JobCategoryCode": series, "WhoMayApply": "Public", "SortField": "closedate", "SortDirection": "Asc", "ResultsPerPage": 250, "Page": page, }) r.raise_for_status() items = r.json()["SearchResult"]["SearchResultItems"] past_window = False for it in items: job = it["MatchedObjectDescriptor"] closes = closes_at(job) if closes < now: continue # already closed  if closes > cutoff: past_window = True # sorted by close date, so the rest are later  break if it["MatchedObjectId"] in rows: rows[it["MatchedObjectId"]]["series"] += f";{series}" continue pay = job["PositionRemuneration"][0] rows[it["MatchedObjectId"]] = { "closes": closes.strftime("%a %d %b"), "days_left": (closes.date() - now.date()).days, "series": series, "title": job["PositionTitle"], "agency": job["OrganizationName"], "grade": f'{job["JobGrade"][0]["Code"]}-{job["UserArea"]["Details"]["LowGrade"]}' f'/{job["UserArea"]["Details"]["HighGrade"]}', "pay": f'{pay["MinimumRange"]}-{pay["MaximumRange"]} {pay["RateIntervalCode"]}', "where": job["PositionLocationDisplay"], "url": job["PositionURI"], } if past_window or len(items) < 250: break page += 1 time.sleep(1) rows = sorted(rows.values(), key=lambda r: (r["days_left"], r["title"])) with open("closing_this_week.csv", "w", newline="") as f: w = csv.DictWriter(f, fieldnames=list(rows[0])) w.writeheader() w.writerows(rows) print(f"{len(rows)} public jobs close by {cutoff:%a %d %b} (ET)") for d in range(DAYS + 1): n = sum(r["days_left"] == d for r in rows) if n: print(f" {(now + timedelta(days=d)):%a %d %b}: {n}") 

What to change:

  • SERIES: any four-digit occupational series codes. 0343 and 0201 are just the example.
  • DAYS: 7 for a weekly list, 14 if your readers need more notice.
  • Drop "WhoMayApply": "Public" if you also advise current federal employees. Status-only jobs will then be included.

Step 3: Run it

python closing_soon.py 

Output on Monday 2 November 2026 (run at 3:46 a.m. ET):

211 public jobs close by Mon 09 Nov (ET) Mon 02 Nov: 70 Tue 03 Nov: 41 Wed 04 Nov: 25 Thu 05 Nov: 27 Fri 06 Nov: 40 Sat 07 Nov: 6 Sun 08 Nov: 2 

Two lines of closing_this_week.csv from that run:

closes,days_left,series,title,agency,grade,pay,where,url Mon 02 Nov,0,0201,Compensation and Leave Program Manager,"Treasury, Departmental Offices",GS-14/14,125776-187093 PA,... Mon 02 Nov,0,0201,HR Policy Specialist (Recruitment and Placement),Office of Human Resources Management,GS-14/14,127829-197200 PA,... 

Friday was busy too: 40 of the 211 closed on Friday 6 November.

Step 4: Schedule it for Monday morning

# 07:00 every Monday, server time 0 7 * * 1 cd /path/to/script && USAJOBS_KEY=... USAJOBS_EMAIL=... python closing_soon.py 

Then email or share closing_this_week.csv. Re-run it midweek if you need to: a Monday list goes stale faster than you'd think.

Things that will catch you out

  • Closing early. The close date is the latest a job can close, not a promise. Agencies can close an announcement early or remove it, and an applicant cut-off usually closes it that night, once the limit is reached. Tell people to open the url and check before they spend an evening on an application.
  • Jobs that stay open for months. 21 of the 325 announcements had application windows longer than six months, some running into fall 2027. They only reach a "closing this week" list near their end date. If your readers want standing openings, run a separate list sorted by opendate instead.
  • Grades like SL-00/00. Senior-level (SL), Senior Executive (ES) and some other pay plans, such as AD, don't use GS grades, so low and high grade come back as 00. Read the pay range instead.
  • One job, several series. An announcement can list more than one occupational series. The script keys rows by job ID, so a job found under two of your series appears once with both codes. (In this run none overlapped.)
  • Pay interval. 210 of the 211 rows were PA (per year). One was PH (per hour). Check RateIntervalCode before you compare salaries.
  • 'Public' isn't always everyone. USAJOBS's Who May Apply: Public filter also returns jobs open only to certain groups, such as veterans or military spouses. Check the job's hiring paths on the announcement before you pass it on.

The shortcut (Disclosure: we built this)

If you'd rather not maintain the script, our Apify Actor USAJOBS API (Unofficial) does the same sort and close-date window as input fields. It is a USAJOBS data tool, not an OPM or USAJOBS product.

curl -X POST "https://api.apify.com/v2/acts/yourevenings~government-jobs-api/run-sync-get-dataset-items" \ -H "Authorization: Bearer $APIFY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jobCategoryCodes": ["0343", "0201"], "sortBy": "closingSoonest", "closingWithinDays": 7, "maxResults": 25}' 

On 2 November 2026 that returned 25 jobs, all closing 2 November, each with closesAt, title, organization, payPlan, lowGrade, highGrade, salaryMinAnnualUsd, hiringPaths and url. Raise maxResults to get the whole week.

Pricing is pay per event: $0.002 per job returned, plus Apify's $0.00005 Actor start per run. A 25-job run is about $0.05 at base price. Status rows are free. You can schedule it weekly in Apify, or use monitor mode for alerts: later runs return only jobs you haven't had before, at $0.002 per new job plus $0.01 on each run that finds any.

https://apify.com/yourevenings/government-jobs-api?utm_source=yourevenings&utm_medium=devto&utm_campaign=federal-jobs-closing-this-week

Your Evenings