Skip to content
API v1 preview — endpoints and fields may change before general availability.

Freshness and lifecycle

How fresh is a job, and how do I know when it opened, reposted or closed?

View .md

Every job carries its own timestamps and a lifecycle status. You do not have to trust a freshness claim. You can read it off each record.

Field Set by Meaning Can be null
posted_at The employer Date the employer posted the job, if known. Yes. Many postings do not state it.
first_seen_at Any source Earliest time any source saw the job. No
last_seen_at Any source Latest time any source saw the job. No
last_verified_at Origin check Latest time the job was confirmed live at its origin. Yes. null = never verified at origin.
sources[].first_seen_at One provider When this provider first saw the job. No
sources[].last_seen_at One provider When this provider last saw the job. No

An illustrative job from the spec:

{
"posted_at": "2026-10-08T00:00:00Z",
"first_seen_at": "2026-10-08T06:40:00Z",
"last_seen_at": "2026-10-11T06:10:00Z",
"last_verified_at": "2026-10-11T06:10:00Z",
"status": "open",
"closed_reason": null,
"repost_count": 0
}

The canonical first_seen_at is the earliest of the sources[].first_seen_at values. The canonical last_seen_at is the latest of the sources[].last_seen_at values. So adding sources can only make a job look earlier-found and more recently seen, never staler.

You want Use
“New jobs since my last sync” first_seen_at. It is always set, and a repost does not reset it.
“How old is the opening?” posted_at when set, else first_seen_at.
“Is it still up?” status, then last_verified_at for proof from the origin.
“How stale is this record?” Now minus last_seen_at.
“Which provider found it first?” The sources[] entry with the earliest first_seen_at.

A job is open or closed. When it closes, closed_reason says why.

status closed_reason Meaning
open null Live. closed_reason is always null while open.
closed filled The role was filled.
closed expired The listing ran out.
closed removed The listing was taken down.
closed unknown It is gone, the reason is not known.

A re-listed job is not a new job. It keeps its id and repost_count goes up. See Canonical jobs.

Searches return only open jobs by default. Send filters.include_closed: true to get closed ones too, for example when you backfill history or reconcile a CRM.

Terminal window
curl https://api.betterjobs.cc/v1/jobs/search \
-H "Authorization: Bearer $BETTERJOBS_API_KEY" \
-H "BetterJobs-Version: 2026-10-01" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"company_domain_or": ["acme-robotics.example"],
"posted_within_days": 30,
"include_closed": true
},
"waterfall": { "max_credits": 100 },
"limit": 100
}'

Instead of polling, watch a company or a saved search. Each change arrives as a typed event:

EventWhat happenedWhat to dodataCost
job.openedA new canonical job appeared for a watched company or saved search.Trigger outbound. This is the only event that should start a sequence.job (full Job)1 credit
job.repostedThe same job was re-listed. repost_count went up.Do not re-trigger outbound. Update your copy of the job only.job (id, title, company, status, repost_count)Free
job.closedThe job is no longer live. closed_reason says why: filled, expired, removed or unknown.Stop sequences tied to this job. Mark it closed in your CRM.job (id, title, company, status, closed_reason)Free
job.updatedA field on an open job changed, for example salary or location.Upsert the job by id. No outbound action.job (full Job)Free

Only job.opened should start outbound. See Events and Webhooks.

BetterJobs is only as fresh as the sources that see a job first. Each partner provider publishes its own refresh claims. They are theirs, not measured by BetterJobs:

SourceRefresh, as publishedPer
ReqbeatRefresh: Corpus refreshed every 3 hoursper Reqbeat docs
SignalsAPIRecheck: Sources rechecked every 15 minutesper SignalsAPI docs
TheirStackDiscovery: 73% of jobs discovered the same day, 91% by the end of the next dayper TheirStack docs
JobsPipeFreshness: Under 6h on Builder, under 1h on Scaleper JobsPipe docs
CoresignalRecheck: Active postings rechecked within 24hper Coresignal docs
TechmapFeeds: Daily country feeds via AWS Data Exchangeper Techmap (jobdatafeeds.com)

The BetterJobs index refresh rate will be published at GA. The freshest_first strategy asks the fastest-refreshing sources first. See the waterfall.