Platform

Alerts

Posts new job listings and upcoming hackathons to Discord. An org adds feeds. Each feed reads one source on a schedule and posts the new items to one Discord webhook.

Feeds

KindSourceItem key
github_jobsThe job table in a GitHub repo's README (Company, Role, Location, Application/Link, Date Posted), as in the internship and new grad listsA hash of company, role, first location, and link with no tracking parameters
hackathonsHack Club, Euro-Hackathons and HackalistThe event name, in lowercase

The first run of a feed records all current items and posts none. Thus a new feed does not post hundreds of old listings. Later runs post up to 25 new items, with half a second between posts. If a post fails, the item stays new and goes out on the next run.

Routes

All routes are under /api/alerts/<org>, for officers of the org. The alerts switch turns them off.

RouteDoes
GET /feedsEach feed with its schedule, last run, last error and number of posts
GET /feeds/<key>One feed
PUT /feeds/<key>Creates (201) or updates (200) a feed. Body below
DELETE /feeds/<key>Deletes the feed, its posted items and its webhook secret
GET /feeds/<key>/historyThe last 50 runs (time, duration, items found, new and posted, error) and the last 50 items the feed posted or recorded
POST /feeds/<key>/runStarts a run now and returns 202. With {"post_existing": true}, a first run posts the current items
GET /presetsThe feeds that packs offer, with the kind and config to send to PUT /feeds/<key>, and added when the org has a feed with that key
{
  "kind": "github_jobs",
  "webhook_url": "https://discord.com/api/webhooks/<id>/<token>",
  "every_hours": 3,
  "enabled": true,
  "config": {"repo": "vanshb03/Summer2026-Internships", "label": "Internship"}
}
  • The key has lowercase letters, digits and dashes, 40 characters or fewer.
  • A new feed needs webhook_url. Platform keeps it as the org secret alert_webhook_<key> and never returns it. A route shows only if it is set.
  • You cannot change kind after you create the feed.
  • every_hours is 1 to 168, default 3.
  • On the Alerts page of the dashboard, New feed > Start from fills the form from a pack feed, such as the internship and hackathon feeds of the careers pack.

github_jobs config:

FieldDefaultDoes
reporequiredowner/name on GitHub
branchmainThe branch to read
pathREADME.mdThe Markdown file with the table
labelJobThe word in the post title, such as Internship
skip_closedtrueLeaves out roles marked closed
max_age_days2Leaves out rows with an older Date Posted. 0 turns off this check

hackathons config:

FieldDefaultDoes
sourcesall threeOne or more of hackclub, euro_hackathons, hackalist
min_days_ahead0Leaves out events that start sooner
max_days_ahead90Leaves out events that start later

A hackathon feed fails only if all its sources fail. MLH and Devpost refuse automated requests, so they are not sources.

Schedule

The alerts.run_due job runs every 15 minutes. It runs each enabled feed whose every_hours has passed since its last run, in orgs that have the module on. A failed run keeps its reason in last_error. Each run, scheduled or started with Run now, adds a row to alert_runs; Platform keeps the last 50 for each feed. The next run occurs at the next due time.

Move from a webhook script

  1. If the module is off for the org, turn it on: flask --app main org modules <prefix> --on alerts.
  2. Make a Discord webhook for each channel, or use the webhooks you have.
  3. PUT one feed for each source. The first run records the current listings, so nothing is posted two times.
  4. Stop the schedule of the old script.

On this page