Check for eBay Deals
Watches a list of eBay searches once an hour and posts a single alert to a Discord channel when a new item falls under your price ceiling. Live searches go through eBay's official Browse API. There is also an offline fixture mode for testing without touching eBay or Discord.
Status: deployed as a Docker container and running. The live image has completed production scans and delivered alerts.
Source repository ยท Setup, configuration, and run instructions
What counts as a deal
- US marketplace, US item location, fixed price, free shipping.
- Price is an exact USD amount at or below the ceiling in your CSV row.
- Parts-only listings are skipped.
- Per scan, each search row alerts on the cheapest eligible item it has not alerted before.
- An item alerts once, ever. A price drop on an item you already alerted on is ignored.
- Each query reads one page of up to 200 results sorted by price. Listings outside that page are not seen.
This is a price ceiling watcher, not a discount finder. It does not know an item is a bargain, only that it is under your number.
How it runs
- Scans about once an hour, measured from the end of the previous scan.
- Delivery is quiet between 02:00 and 12:00 UTC. Scans keep running and new finds are stored as pending, then sent once the window closes.
- Pending alerts are sent as they were discovered. Availability and price are not rechecked before sending.
- Sent history and pending alerts live in a SQLite file under
--data-dir, which also holds the lockfile and logs. - Delivery is at least once. A failed send stays pending and retries next run, so a crash in a narrow window can produce a duplicate alert.
- A second instance sharing the same data directory exits with code 3.
Offline fixture smoke:
.venv/bin/python check_for_ebay_deals.py --once --dry-run \
--fixture-dir tests/fixtures/offline-scan \
--csv tests/fixtures/offline-scan/smoke.csv \
--data-dir /tmp/deals-fixture
A dry run prints alert identities, opens state read-only, and sends nothing. Note that a dry run without fixtures still contacts eBay, so it needs API credentials. Fixture runs use a stub transport that prints deliveries instead of posting to Discord.
Configuration
Three things are needed: the search CSV (max_price,friendly_name,search_query), a Discord bot token plus channel ID, and an eBay production application credential file (App ID and Cert ID) stored as owner-only JSON with mode 0600. Docker mounts the CSV and secrets read-only and keeps state on a named volume at /data. Details and exit codes are in the README.
Known rough edges
- If the Discord channel cannot be fetched, alerts stay pending and the next run retries, but a
--oncerun does not report that as a failure in its exit code. - Corrupt or unsupported state files cause a loud startup refusal rather than a silent reset, so dedupe history is never lost by accident. Recovery is manual.