New to Kestra?
Use blueprints to kickstart your first workflows.
List Ashby job postings, alert Slack when publicly listed roles have been open past a threshold, and log the result for recruiting ops.
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.
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.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.route (io.kestra.plugin.core.flow.If):summary logs the count and severity, closing the governance cycle.errors alerts Slack if the flow itself fails, for example an expired API key.isListed and publishedDate, two fixed fields in Ashby's documented API
response, rather than status string values that can vary by account configuration.jobpostings.List used for a
governance check rather than a one-off export.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.
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.
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.| 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.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.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.ASHBY_API_KEY and SLACK_WEBHOOK_URL secrets.summary logs a count.stale_days below a real posting's age to confirm alert fires with its title.weekly trigger once the threshold matches your hiring process.departmentName so each hiring manager's team sees only their own stale
postings.locationName against a headcount budget to flag postings that are both
stale and over budget for their location.