Daily sanctions and PEP monitoring digest in Slack

By General Input

Watch a Notion list of high-risk people and companies for new sanctions, PEP, or watchlist activity, and get a Slack alert only when something actually changes.

Integrations

  • OpenSanctions
  • Notion
  • Slack Bot

Type

Agentic Task

Categories

  • Operations

Build me an agent workflow that runs every day at 6am Eastern Time and monitors a Notion database called "People & Companies of Interest" for new sanctions, PEP, debarment, or watchlist activity, then posts a delta digest to a Slack channel called #watchlist-updates. This is ongoing monitoring, not point-in-time screening. The whole point is to compare today's OpenSanctions snapshot for each watched entity against what we stored on the Notion page on the previous run, and only alert when something actually changed.

Trigger: cron, daily at 06:00 America/New_York.

Step 1. Use Notion's Query a Data Source operation against the People & Companies of Interest database to pull every page. Each page represents one person or company being watched and should have at least these properties: Name, Entity Type (Person or Company / Organization), Country, OpenSanctions Entity ID (text, may be empty for new rows), Last Known Status (text), Last Known Sanctions (text or rich text, our stored snapshot), Last Known Associates (text or rich text, our stored snapshot), Entity URL (URL), and Last Checked At (date). Paginate through all results.

Step 2. For each Notion row, resolve the current OpenSanctions entity:

If the row already has an OpenSanctions Entity ID, call OpenSanctions Fetch Entity with that ID. If the response is a 308 redirect (the entity was merged into a new canonical ID), follow the Location header to the new ID and remember the new canonical ID so we can write it back to Notion. If the ID truly 404s, fall back to Step 2b.

If the row does not have an OpenSanctions Entity ID yet (or we just got a 404), call OpenSanctions Match Entities against the default dataset using the row's Name, Entity Type (schema Person, Company, or Organization), and Country. Take the top match above the default confidence threshold. If nothing matches, mark the row as "No match found" in Last Known Status and move on without posting an alert. If a match is found, use that ID going forward.

Step 3. For the resolved entity, call OpenSanctions Fetch Adjacent Entities to pull richness: current sanctions list memberships, PEP designations, debarments, and associates / family. Build a compact "current snapshot" string for sanctions and another for associates.

Step 4. Compare the current snapshot to what's stored on the Notion page (Last Known Sanctions and Last Known Associates). A row "genuinely changed" if any of the following is true since the previous run: a new sanction designation appeared, a sanction was lifted, the entity moved from clear to PEP or vice versa, a new associate appeared, or the canonical OpenSanctions ID changed because of a merge.

Step 5. Use Notion Update a Page on every row processed to refresh: OpenSanctions Entity ID (in case of a merge), Last Known Status (concise summary like "Clear", "PEP", "Sanctioned by OFAC SDN + EU", or "Debarred by World Bank"), Last Known Sanctions (the new snapshot), Last Known Associates (the new snapshot), Entity URL (the canonical opensanctions.org URL for this entity), and Last Checked At (now in ISO 8601). Do this whether the row changed or not, so we always have a fresh stamp.

Step 6. If at least one row genuinely changed, use Slack Bot Send a Message to post a single digest to #watchlist-updates. The message should be a short narrative grouped by entity: name in bold, one or two sentence summary of what changed (e.g. "Added to the EU consolidated sanctions list on 2026-06-28" or "Now flagged as a PEP after taking office as Minister of Energy"), a link to the OpenSanctions entity, and a link to the Notion page for that row. Use Slack mrkdwn formatting (single asterisks for bold, <url|text> for links). If nothing changed across the whole database that day, do not post anything.

Other behavior notes: be resilient to OpenSanctions rate limits (back off on 429); never overwrite the OpenSanctions ID with empty if a fetch fails, just skip that row and try again next run; treat the comparison as text-set diffing, not string equality, so reordering of the same items isn't reported as a change.

Related prompts

Explore more prompts
A brand asset library your marketing team actually searchesTurn Mailjet email clicks into ranked HubSpot follow-upsClean out the Looker dashboards and Looks nobody opensLiveKit live operations console for room moderationWake up dormant Keap leads with a researched reasonLiveChat coverage board for planning next week's shiftsPhone routing control panel for LiveKit voice agentsLinkedIn Ads budget pacing dashboard for every client accountGive your team Looker numbers without buying more seatsPause marketing emails to escalated customers, then restore them