Schedule icon
Return icon
Download icon
Get icon
Queries icon
Set icon
If icon
Loop icon
Request icon
SlackIncomingWebhook icon
Log icon

Watch Cited Papers for Retractions, Expressions of Concern and Corrections via Crossref

Weekly Crossref check of cited DOIs for retractions, concerns and corrections, deduplicated through the KV store, with per-DOI status CSV and Slack alerts.

Categories
Data

Model cards, clinical guidelines and policy briefs cite papers that nobody reads again after publication, yet Crossref receives a few hundred retraction notices a week and the citation keeps pointing at a result that no longer stands. Crossref records every retraction, partial retraction, expression of concern and correction against the original DOI in the updated-by array of the work record, including the notices from the Retraction Watch database. This flow turns that array into a weekly check: one request for the whole watchlist, a DuckDB pass that flattens and classifies the notices, a KV-backed memory of what was already reported, and one alert per new notice with the notice title, date and link.

How it works

  1. A weekly Schedule trigger (Tuesday 06:00 UTC) runs the check; dois is a semicolon-separated list and normalise_dois (Return) strips spaces so hand-edited lists work.
  2. fetch_works (HTTP Download) calls api.crossref.org/works once with a repeated filter=doi: for every DOI and select limited to the fields needed, including updated-by. If contact_email is set it is appended as mailto= and put in the User-Agent, which moves the request to Crossref's polite pool.
  3. previous_notices (KV Get, errorOnMissing: false) reads the JSON array of (doi, notice_doi, update_type) triples reported by earlier runs; it is missing on the first run.
  4. classify (DuckDB Queries, fetchType: FETCH_ONE) parses the response with read_text and from_json, flattens each work's updated-by into one row per notice (a notice reported by both the publisher and Retraction Watch is one row, reported_by keeps both sources), left-joins the watchlist so a DOI Crossref does not know becomes NOT_FOUND, and anti-joins the notices against the ones already seen. Each DOI gets a status: RETRACTED, PARTIALLY_RETRACTED, EXPRESSION_OF_CONCERN, CORRECTED, CLEAN or NOT_FOUND. The per-DOI report is written as CSV through outputFiles; the single result row carries the counts, the new notices to alert on as JSON and the merged seen set.
  5. save_notices (KV Set) stores the merged set, so each notice is reported exactly once and DOIs removed from the list do not lose their history.
  6. report_new_notices (If) runs each_notice (Loop) over the new alert notices when there are any. Each iteration calls fetch_notice (HTTP Request) for the notice record so the message has the notice title, then posts to Slack (allowFailure, so a missing webhook warns instead of failing) and logs a WARN line. Retractions, partial retractions, expressions of concern, removals and withdrawals always alert; corrections and errata alert only when alert_on_corrections is true, otherwise they are counted and kept in the report.
  7. warn_not_found logs the DOIs Crossref does not know (runIf on the count), which catches typos in a citation list.
  8. summary logs the counts and the flow exposes the summary JSON and the status CSV as outputs.

What you get

  • A CSV per run with one row per watched DOI: title, venue, year, citation count, status, number of notices, latest notice date and the list of notice DOIs.
  • One alert per new notice, never repeated, with the paper, the notice type, the notice date, who reported it (publisher, Retraction Watch or both) and doi.org links to both records.
  • NOT_FOUND for DOIs Crossref has no record of, so a mistyped citation fails loudly instead of passing as clean.
  • State in the KV store only: no database, no files to manage, a few kilobytes for hundreds of papers.

Who it's for

  • ML and data science teams that cite papers in model cards and want to know if a method they rely on was retracted.
  • Medical writers, guideline committees and systematic reviewers who maintain a reference list over years.
  • Research software engineers and librarians who run integrity checks on institutional publication lists.

Why orchestrate this with Kestra

  • Download plus DuckDB inputFiles turns a JSON API response into tables without a script; the classification is SQL you can read in the flow.
  • The KV store holds the seen set between runs, so "report once" needs no database.
  • Loop runs one alert per notice with its own HTTP lookup, and allowFailure keeps a missing webhook or notice record from failing the check.
  • The watchlist is an input: the same flow serves one model card or a whole lab's publication list.

Prerequisites

  • Kestra 2.0 with the JDBC DuckDB plugin and, for the alert, the Slack plugin (io.kestra.plugin.slack.notifications.SlackIncomingWebhook).
  • Outbound HTTPS to api.crossref.org; the REST API needs no key. Set contact_email for the polite pool on larger lists.
  • DOIs must be registered with Crossref (most journals and conference proceedings are; DataCite DOIs for datasets are not and show as NOT_FOUND).

Secrets

  • SLACK_WEBHOOK_URL: Slack incoming webhook for the alert (optional; without it the notify task warns and the check still succeeds).

Quick start

  1. Import the flow and click Execute with the defaults. The list holds two clean papers and two retracted ones (one 2019 oncology paper retracted in 2021, and the 1998 Lancet paper retracted in 2010 after a 2004 partial retraction). The first run is a baseline: it reports retracted 2, clean 2, finds 3 notices and alerts on the 2 retractions.
  2. Execute again: new_notices 0, the nothing_new branch runs.
  3. Add a DOI with a typo to the list and run: it shows as NOT_FOUND in the CSV and warn_not_found names it.
  4. Set alert_on_corrections to true after deleting the KV key cited_paper_notices_seen: the 2004 correction notice now alerts as well.
  5. Replace the defaults with your own DOIs, add SLACK_WEBHOOK_URL as a secret, set contact_email and leave the weekly schedule on.

How to extend

  • Read the DOI list from a namespace file or a Google Sheet instead of an input, so authors edit the list without touching the flow.
  • Open a Jira or GitHub issue per notice with the Jira or GitHub plugins in place of, or in addition to, the Slack message.
  • Append each run's status CSV to a warehouse table to keep a history of when each paper changed status.
  • Lower the schedule to daily for lists under active review; one request per run keeps it well inside Crossref's limits.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.