The first thing most SDRs do with a funding alert is... nothing, because it
lands in an email digest three weeks after the fact and 40 other companies
in that digest already got pitched by five other vendors.
This is a ~40 line Python script that checks for new funding signals every
morning and posts the ones that match your ICP straight into a Slack
channel — so the "just raised money" alert actually arrives while it's
still useful.
What you need
- A free Funding Signals API key (self-serve, no card).
- A Slack Incoming Webhook URL for the channel you want alerts in (Slack → your workspace → Apps → search "Incoming Webhooks" → Add to Slack → pick a channel → copy the webhook URL).
-
requestsinstalled (pip install requests).
The script
import requests
import os
FS_API_KEY = os.environ["FUNDING_SIGNALS_KEY"]
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
# tune this to your ICP
PARAMS = {
"min_score": 80,
"min_raise": 3_000_000,
"industry": "technology",
"has_contact": "true",
"limit": 10,
}
def fetch_signals():
resp = requests.get(
"https://funding-signals-api.onrender.com/v1/signals",
headers={"X-API-Key": FS_API_KEY},
params=PARAMS,
)
resp.raise_for_status()
return resp.json()
def post_to_slack(signal):
text = (
f"*{signal['company_name']}* just raised "
f"${signal['amount_usd']:,} ({signal['industry']}) — score "
f"{signal['score']}/100\n"
f"<https://funding-signals-api.onrender.com/v1/signals/{signal['id']}/lead"
f"?utm_source=slackbot|View enriched lead>"
)
requests.post(SLACK_WEBHOOK, json={"text": text})
def main():
for signal in fetch_signals():
post_to_slack(signal)
if __name__ == "__main__":
main()
Set the two environment variables and run it once to sanity-check the
output, then point it at a scheduler.
Making it run daily
Simplest option: a GitHub Actions workflow in the same repo as the script
(no server to babysit).
# .github/workflows/funding-alerts.yml
name: funding-alerts
on:
schedule:
- cron: "0 13 * * 1-5" # 9am ET, weekdays
workflow_dispatch: {}
jobs:
alert:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 - uses: actions/setup-python@v5 with:
python-version: "3.12"
- run: pip install requests
- run: python alert.py
env:
FUNDING_SIGNALS_KEY: ${{ secrets.FUNDING_SIGNALS_KEY }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Add the two secrets in the repo's Settings → Secrets → Actions, and that's
the whole pipeline: SEC filing → scored signal → Slack message, with no
server and no cron box to maintain.
Avoiding duplicate alerts
The API doesn't track what you've already seen, so on a fresh run every
signal in the current window will post again. Cheapest fix: keep a small
JSON file of seen IDs, commit it back after each run.
import json
from pathlib import Path
SEEN_FILE = Path("seen_ids.json")
def load_seen():
if SEEN_FILE.exists():
return set(json.loads(SEEN_FILE.read_text()))
return set()
def save_seen(ids):
SEEN_FILE.write_text(json.dumps(sorted(ids)))
def main():
seen = load_seen()
signals = fetch_signals()
new = [s for s in signals if s["id"] not in seen]
for signal in new:
post_to_slack(signal)
save_seen(seen | {s["id"] for s in new})
If you're running this in GitHub Actions, add a commit-and-push step at the
end of the job so seen_ids.json persists between runs.
Where to take it from here
Same pattern works for a Discord webhook, a CRM sync (dump straight into
HubSpot/Airtable instead of Slack), or per-rep channels filtered by
industry. The API call is the same either way — only post_to_slack
changes.
Docs: funding-signals-api.onrender.com/docs
Prefer no code at all? Grab the free lead tracker template instead.
Top comments (0)