List icon
OutputValues icon
If icon
SlackIncomingWebhook icon
Log icon
Schedule icon

Ashby Stale Open Job Posting Sentinel

List Ashby job postings, alert Slack when publicly listed roles have been open past a threshold, and log the result for recruiting ops.

Categories
BusinessCore

A job posting that has been publicly listed for months without closing is either a role that quietly stalled, a budget line nobody cleaned up, or a candidate experience problem, people keep applying to a role that is not really moving. Ashby's own dashboard shows every open posting if someone goes looking; it does not page anyone when one has simply been sitting there too long. This blueprint lists every posting and flags the ones that have.

This blueprint was created by Mohit Jeswani.

How it works

  1. list_job_postings (io.kestra.plugin.ashby.jobpostings.List) fetches every job posting from Ashby's jobPosting.list endpoint, listed and unlisted. Read-only; nothing in Ashby is changed. allowFailure: true covers an API or auth error without failing the flow outright.
  2. evaluate (io.kestra.plugin.core.output.OutputValues) filters to postings where isListed is true and publishedDate is older than stale_days, counting them and collecting their titles with a jq filter.
  3. route (io.kestra.plugin.core.flow.If):
    • compliant: logs that nothing is stale.
    • alert: posts the count and titles to Slack.
  4. summary logs the count and severity, closing the governance cycle.
  5. errors alerts Slack if the flow itself fails, for example an expired API key.

What you get

  • A recurring answer to "which open roles have been sitting the longest", named by title, not just a count.
  • A check built on isListed and publishedDate, two fixed fields in Ashby's documented API response, rather than status string values that can vary by account configuration.
  • A read-only check with zero risk of touching a real job posting.

Who it's for

  • Recruiting ops and talent teams running Ashby who want stale, publicly visible postings surfaced automatically instead of found during a quarterly audit.
  • Teams evaluating the Ashby plugin who want a worked example of jobpostings.List used for a governance check rather than a one-off export.

Why orchestrate this with Kestra

Ashby has no native alert for posting age; the only way to know is to open the postings list and eyeball publish dates. Kestra keeps stale_days as a flow input, turns the check into a Slack page naming the actual roles, and keeps a full execution history of every run.

Prerequisites

  • An Ashby account with an API key that has access to the Job Posting API.
  • At least one publicly listed job posting to confirm the filter logic against.
  • A Slack incoming webhook URL.

This flow calls the Ashby API directly over HTTPS; there is no official local Ashby emulator, so list_job_postings cannot be exercised against a local Docker container. Validate against a real Ashby account with a mix of old and recent postings.

Secrets

  • ASHBY_API_KEY: the Ashby API key used by list_job_postings, sent as HTTP Basic Auth. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_ASHBY_API_KEY.
  • SLACK_WEBHOOK_URL: used by alert and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Default Purpose
stale_days 60 Age past which a listed posting is reported stale
max_stale_count 1 Matched-posting count that triggers the Slack alert

Outputs

  • {{ outputs.list_job_postings.rows }}: every job posting (id, title, status, isListed, publishedDate, departmentName, locationName, and more).
  • {{ outputs.evaluate.values.stale_count }} / .stale_titles: how many postings are stale and their titles, semicolon-joined.
  • {{ outputs.evaluate.values.severity }}: OK, STALE_POSTINGS_FOUND, or CRITICAL.

Pitfalls

  • publishedDate can be null for a posting that has never been published; this check only ever flags postings that both have a publishedDate and are currently isListed, so a drafted-but-never-published posting is correctly excluded, not a false negative.
  • jobPosting.list returns every posting in one response with no documented pagination parameters on this task; an account with an extremely large posting history fetches everything on every run.
  • isListed reflects whether the posting is currently public, not whether its role is filled. An unlisted posting that is still technically open but was manually hidden will not be flagged by this check.

Quick start

  1. Add the ASHBY_API_KEY and SLACK_WEBHOOK_URL secrets.
  2. Run the flow with the defaults and confirm summary logs a count.
  3. Lower stale_days below a real posting's age to confirm alert fires with its title.
  4. Enable the weekly trigger once the threshold matches your hiring process.

How to extend

  • Group the alert by departmentName so each hiring manager's team sees only their own stale postings.
  • Add a second, longer threshold that escalates to a different Slack channel for postings stale well past the first alert.
  • Cross-reference locationName against a headcount budget to flag postings that are both stale and over budget for their location.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.