A federal opportunity monitor is one of the few genuinely high-value things to build on public data: the notices are published because the law requires it, they are timestamped, and missing one has a concrete cost. Here is a shape that works.
The shape of a monitor
A daily run over a publication window, filtered to your classification codes and set-asides, deduplicated by notice_id, with alerts scheduled only against deadlines that are real instants.
Everything below is a consequence of one property: SAM.gov notices are immutable once published. An amendment creates a new notice that links back to the previous one, so nothing you already stored goes stale.
The filters that earn their place
pscCodesandnaicsCodes— 97.8% and 96.1% filled. Be generous with the list; the filter is server-side so unused codes cost nothing.setAsideCodes— only if you hold a designation, and remember that it removes the 53.9% of notices that are open competition.noticeTypes—o,kandrfor live opportunities. Award notices are useful for market intelligence and useless for bidding.officeStatesrather thanplaceOfPerformanceStatesif geography matters: the latter is stated on only about a third of notices, so filtering on it silently drops two thirds.
The publication window and the overlap
About 2,500 notices are published per calendar day, and sweeping is by publication date — one day per request, newest first. A daily run with publishedWithinDays: 3 gives you two days of overlap, so a missed run does not create a gap.
The overlap is free in the sense that matters: rows are deduplicated by notice_id before delivery, so you are never charged for a duplicate.
Immutability makes caching safe
maxCacheAgeDays defaults to 90, which would be reckless on almost any other target in this catalogue — a Workana proposal count is wrong within hours.
Here it is correct, because a published notice does not change. What changes is that a new notice appears linking back to it, which your next sweep picks up as a new row with a parent_notice_id. Every row still declares from_cache, fetched_at and data_age_hours, so the decision stays visible.
Scheduling against the right field
The one place a monitor can be actively harmful is the deadline. Schedule alarms only where response_due_precision = "instant" — 61.0% of deadlines. For the 38.8% that are date-only, put response_due_local in front of a person.
-- Automated countdown: only real instants
INSERT INTO alerts (notice_id, fire_at)
SELECT notice_id, response_due_utc - interval '3 days'
FROM notices
WHERE response_due_precision = 'instant'
AND response_due_utc > now();
-- Human review queue: dates without times
SELECT notice_id, title, response_due_local
FROM notices
WHERE response_due_precision = 'date_only'
ORDER BY response_due_local;Why midnight UTC is not a deadline.
When to fetch documents
Not on the monitoring sweep. Attachments cost one request per notice regardless of whether the notice has any, and the hit rate is 36.7% overall and 14% on award notices.
The efficient shape is two stages: monitor without attachments, then run a second, tightly filtered job with scrapeAttachments: true over the handful of notices you actually care about. That is the same two-stage pattern as the Nextdoor reconnaissance run.
What it costs to run daily
At $0.0025 per notice, a well-filtered daily sweep returning 50 to 200 new notices is 13 to 50 cents a day — under fifteen dollars a month for continuous coverage of your slice of federal procurement, with the solicitation text included.
The second-stage attachment job on, say, ten notices a day adds five cents. The cost of this pipeline is not the data; it is deciding what to do with what it finds.


