[{"data":1,"prerenderedAt":427},["ShallowReactive",2],{"navigation":3,"blog-navigation":109,"\u002Fblog\u002Fclosed-job-postings":149,"\u002Fblog\u002Fclosed-job-postings-surround":423},[4,23,47,68,98],{"title":5,"path":6,"stem":7,"children":8,"icon":22},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Authentication","\u002Fdocs\u002Fgetting-started\u002Fauthentication","1.docs\u002F1.getting-started\u002F2.authentication","i-lucide-key",{"title":18,"path":19,"stem":20,"icon":21},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","1.docs\u002F1.getting-started\u002F3.quick-start","i-lucide-rocket",false,{"title":24,"icon":22,"path":25,"stem":26,"children":27,"page":22},"API Reference","\u002Fdocs\u002Freference","1.docs\u002F2.reference",[28,32,37,42],{"title":24,"path":29,"stem":30,"icon":31},"\u002Fdocs\u002Freference\u002Foverview","1.docs\u002F2.reference\u002F1.overview","i-lucide-book-open",{"title":33,"path":34,"stem":35,"icon":36},"Jobs","\u002Fdocs\u002Freference\u002Fjobs","1.docs\u002F2.reference\u002F2.jobs","i-lucide-briefcase",{"title":38,"path":39,"stem":40,"icon":41},"Companies","\u002Fdocs\u002Freference\u002Fcompanies","1.docs\u002F2.reference\u002F3.companies","i-lucide-building-2",{"title":43,"path":44,"stem":45,"icon":46},"Data Types","\u002Fdocs\u002Freference\u002Fdata-types","1.docs\u002F2.reference\u002F4.data-types","i-lucide-list",{"title":48,"path":49,"stem":50,"children":51,"icon":22},"Code Examples","\u002Fdocs\u002Fcode-examples","1.docs\u002F3.code-examples\u002F1.index",[52,54,59,63],{"title":48,"path":49,"stem":50,"icon":53},"i-lucide-code",{"title":55,"path":56,"stem":57,"icon":58},"JavaScript","\u002Fdocs\u002Fcode-examples\u002Fjavascript","1.docs\u002F3.code-examples\u002F2.javascript","i-lucide-braces",{"title":60,"path":61,"stem":62,"icon":53},"Python","\u002Fdocs\u002Fcode-examples\u002Fpython","1.docs\u002F3.code-examples\u002F3.python",{"title":64,"path":65,"stem":66,"icon":67},"cURL","\u002Fdocs\u002Fcode-examples\u002Fcurl","1.docs\u002F3.code-examples\u002F4.curl","i-lucide-terminal",{"title":69,"icon":22,"path":70,"stem":71,"children":72,"page":22},"Guides","\u002Fdocs\u002Fguides","1.docs\u002F4.guides",[73,78,83,88,93],{"title":74,"path":75,"stem":76,"icon":77},"Filter Jobs","\u002Fdocs\u002Fguides\u002Fhow-to-filter-jobs-by-skills-location-and-salary","1.docs\u002F4.guides\u002F1.how-to-filter-jobs-by-skills-location-and-salary","i-lucide-filter",{"title":79,"path":80,"stem":81,"icon":82},"Fetch All Jobs","\u002Fdocs\u002Fguides\u002Fcursor-pagination-for-large-job-datasets","1.docs\u002F4.guides\u002F2.cursor-pagination-for-large-job-datasets","i-lucide-chevrons-right",{"title":84,"path":85,"stem":86,"icon":87},"Incremental Sync","\u002Fdocs\u002Fguides\u002Fautomate-daily-job-sync-with-incremental-updates","1.docs\u002F4.guides\u002F3.automate-daily-job-sync-with-incremental-updates","i-lucide-refresh-cw",{"title":89,"path":90,"stem":91,"icon":92},"Rate Limits","\u002Fdocs\u002Fguides\u002Fhow-to-handle-api-rate-limits","1.docs\u002F4.guides\u002F4.how-to-handle-api-rate-limits","i-lucide-gauge",{"title":94,"path":95,"stem":96,"icon":97},"Build a Job Board","\u002Fdocs\u002Fguides\u002Fhow-to-build-a-job-board","1.docs\u002F4.guides\u002F5.how-to-build-a-job-board","i-lucide-layout-grid",{"title":99,"path":100,"stem":101,"children":102,"icon":104},"Webhooks","\u002Fdocs\u002Fwebhooks","1.docs\u002F5.webhooks\u002F1.index",[103,105],{"title":99,"path":100,"stem":101,"icon":104},"i-lucide-webhook",{"title":106,"path":107,"stem":108,"icon":46},"Event reference","\u002Fdocs\u002Fwebhooks\u002Fevent-reference","1.docs\u002F5.webhooks\u002F2.event-reference",[110],{"title":111,"path":112,"stem":113,"children":114,"page":22},"Blog","\u002Fblog","3.blog",[115,122,128,135,142],{"title":116,"path":117,"stem":118,"children":119,"icon":121},"Job Closures","\u002Fblog\u002Fclosed-job-postings","3.blog\u002F5.closed-job-postings\u002F1.index",[120],{"title":116,"path":117,"stem":118,"icon":121},"i-lucide-archive",{"title":123,"path":124,"stem":125,"children":126,"icon":104},"Webhooks Launch","\u002Fblog\u002Fwebhooks","3.blog\u002F3.webhooks\u002F1.index",[127],{"title":123,"path":124,"stem":125,"icon":104},{"title":129,"path":130,"stem":131,"children":132,"icon":134},"Why Job Descriptions Now Come as Plain Text and Markdown","\u002Fblog\u002Fdescription-formats","3.blog\u002F4.description-formats\u002F1.index",[133],{"title":129,"path":130,"stem":131,"icon":134},"i-lucide-file-text",{"title":136,"path":137,"stem":138,"children":139,"icon":141},"How to Build Automated Job Alerts with n8n - Jobven API Tutorial","\u002Fblog\u002Fn8n-job-alerts","3.blog\u002F2.n8n-job-alerts\u002F1.index",[140],{"title":136,"path":137,"stem":138,"icon":141},"i-lucide-workflow",{"title":143,"path":144,"stem":145,"children":146,"icon":148},"What is a Job Posting API?","\u002Fblog\u002Fjob-posting-api","3.blog\u002F1.job-posting-api\u002F1.index",[147],{"title":143,"path":144,"stem":145,"icon":148},"i-lucide-help-circle",{"id":150,"title":151,"authors":152,"badge":156,"body":158,"date":396,"description":397,"extension":398,"head":399,"image":413,"meta":414,"navigation":419,"path":117,"schemaOrg":413,"seo":420,"sitemap":421,"stem":118,"__hash__":422},"posts\u002F3.blog\u002F5.closed-job-postings\u002F1.index.md","When a Job Posting Is Closed, Your Feed Should Know",[153],{"name":154,"description":155},"Peter","Founder, Jobven",{"label":157},"Announcement",{"type":159,"value":160,"toc":390},"minimark",[161,165,169,172,177,193,196,199,203,206,209,220,223,316,319,323,354,361,365,371,383,386],[162,163,151],"h1",{"id":164},"when-a-job-posting-is-closed-your-feed-should-know",[166,167,168],"p",{},"Someone finds a job on your site, writes a cover letter, clicks apply, and lands on a page that says the position is no longer available. They do not conclude that the employer moved fast. They conclude that your listings are stale, and the next time they need a job they go somewhere else.",[166,170,171],{},"Getting new jobs is the easy half of a job feed. Knowing which ones are gone is the half that decides whether people trust what you show them.",[173,174,176],"h2",{"id":175},"closed-roles-leave-the-feed","Closed roles leave the feed",[166,178,179,180,184,185,188,189,192],{},"Jobven re-checks every employer's board on a schedule. When a posting stops appearing across repeated checks, the job's ",[181,182,183],"code",{},"status"," becomes ",[181,186,187],{},"closed",", it drops out of the default job feed, and a ",[181,190,191],{},"job.closed"," event goes out to any webhook subscription that asked for it.",[166,194,195],{},"That means you can keep a clean board without tracking every listing yourself. You are not diffing yesterday's results against today's, and you are not re-fetching a million records to find the handful that went quiet.",[166,197,198],{},"Closed jobs stay fetchable by id, so anything you have already stored can still be resolved. They simply stop being served as current.",[173,200,202],{"id":201},"a-relisted-role-keeps-its-id","A relisted role keeps its id",[166,204,205],{},"Employers put roles back up. A position gets re-approved, a hire falls through, a seasonal listing returns.",[166,207,208],{},"When that happens, the job reopens under the id you already have rather than arriving as a new record. Whatever you stored against that id, your own metadata, saved searches, application records, stays valid.",[166,210,211,212,215,216,219],{},"The event you receive is ",[181,213,214],{},"job.created",", not ",[181,217,218],{},"job.updated",". That is deliberate: you were told the job closed, so on your side there is nothing to apply an update to.",[166,221,222],{},"This is the one part worth checking in your own code. If your handler for a created job does an unconditional insert, a reopened role will arrive as a duplicate:",[224,225,230],"pre",{"className":226,"code":227,"language":228,"meta":229,"style":229},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Handles both a genuinely new job and a reopened one\napp.post('\u002Fwebhooks\u002Fjobven', (req, res) => {\n  const { event, data } = req.body\n\n  if (event === 'job.created') {\n    db.jobs.upsert({ where: { id: data.id }, data })\n  }\n\n  if (event === 'job.closed') {\n    db.jobs.update({ where: { id: data.id }, data: { status: 'closed' } })\n  }\n\n  res.sendStatus(200)\n})\n","js","",[181,231,232,240,246,252,259,265,271,277,282,288,294,299,304,310],{"__ignoreMap":229},[233,234,237],"span",{"class":235,"line":236},"line",1,[233,238,239],{},"\u002F\u002F Handles both a genuinely new job and a reopened one\n",[233,241,243],{"class":235,"line":242},2,[233,244,245],{},"app.post('\u002Fwebhooks\u002Fjobven', (req, res) => {\n",[233,247,249],{"class":235,"line":248},3,[233,250,251],{},"  const { event, data } = req.body\n",[233,253,255],{"class":235,"line":254},4,[233,256,258],{"emptyLinePlaceholder":257},true,"\n",[233,260,262],{"class":235,"line":261},5,[233,263,264],{},"  if (event === 'job.created') {\n",[233,266,268],{"class":235,"line":267},6,[233,269,270],{},"    db.jobs.upsert({ where: { id: data.id }, data })\n",[233,272,274],{"class":235,"line":273},7,[233,275,276],{},"  }\n",[233,278,280],{"class":235,"line":279},8,[233,281,258],{"emptyLinePlaceholder":257},[233,283,285],{"class":235,"line":284},9,[233,286,287],{},"  if (event === 'job.closed') {\n",[233,289,291],{"class":235,"line":290},10,[233,292,293],{},"    db.jobs.update({ where: { id: data.id }, data: { status: 'closed' } })\n",[233,295,297],{"class":235,"line":296},11,[233,298,276],{},[233,300,302],{"class":235,"line":301},12,[233,303,258],{"emptyLinePlaceholder":257},[233,305,307],{"class":235,"line":306},13,[233,308,309],{},"  res.sendStatus(200)\n",[233,311,313],{"class":235,"line":312},14,[233,314,315],{},"})\n",[166,317,318],{},"An upsert keyed on the job id handles both cases and costs nothing extra.",[173,320,322],{"id":321},"status-changes-have-their-own-events","Status changes have their own events",[166,324,325,327,328,331,332,331,335,331,338,331,341,344,345,348,349,344,351,353],{},[181,326,218],{}," does not fire when a job's status changes. It tracks content: ",[181,329,330],{},"title",", ",[181,333,334],{},"salary",[181,336,337],{},"employmentType",[181,339,340],{},"remoteType",[181,342,343],{},"applyUrl"," and ",[181,346,347],{},"expiresAt",". Status movements are carried by ",[181,350,214],{},[181,352,191],{}," instead, so a subscription that only listens for updates will not see a closure.",[166,355,356,357,360],{},"If you filter jobs yourself, ",[181,358,359],{},"status=closed"," returns results you can query directly, which is useful for reconciling a store that has drifted.",[173,362,364],{"id":363},"where-to-start","Where to start",[166,366,367,368,370],{},"If you already receive Jobven webhooks, add ",[181,369,191],{}," to your subscription and confirm your created-job handler upserts. If you are polling, the same information is on the regular API: closed jobs leave the default feed, and you can ask for them explicitly.",[166,372,373,374,378,379,382],{},"The ",[375,376,377],"a",{"href":107},"event reference"," covers the payload shape for each event, and the ",[375,380,381],{"href":124},"webhooks guide"," walks through setting up a subscription from scratch.",[166,384,385],{},"Over a million job postings have passed through Jobven. The ones that close now leave.",[387,388,389],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":229,"searchDepth":242,"depth":242,"links":391},[392,393,394,395],{"id":175,"depth":242,"text":176},{"id":201,"depth":242,"text":202},{"id":321,"depth":242,"text":322},{"id":363,"depth":242,"text":364},"2026-08-25 10:00:00","Jobven closes a job posting when the employer's board stops listing it, sends job.closed, and drops it from the feed. Handle reopened roles without duplicates.","md",{"meta":400},[401,404,407,410],{"name":402,"content":403},"keywords","closed job postings, expired job listings api, detect expired job postings, job closed webhook, job posting expiration, job lifecycle api",{"name":405,"content":406},"og:title","Closed Job Postings: Detect Them and Keep Your Feed Current | Jobven",{"name":408,"content":409},"og:description","Filled roles that linger are the fastest way to lose a reader's trust. Here is how Jobven closes a job posting once the board stops listing it.",{"name":411,"content":412},"twitter:card","summary_large_image",null,{"ogImage":415},{"component":416,"props":417},"OgImageBlog",{"title":418},"When a Job Posting Is Closed",{"title":116,"icon":121},{"title":406,"description":397},{"loc":117},"DJ0pVxNHWjyyX43ie20YMBfwN8zKHcOIICpwa9_5Hnk",[424,413],{"title":129,"path":130,"stem":131,"description":425,"date":426,"icon":134,"children":-1},"Request job descriptions as plain text, markdown or HTML with one query parameter. Precomputed at ingest, so email, search and AI pipelines get what they need.","2026-04-18 00:00:00",1787689862641]