Small Python monitoring service for BuySellVouchers offers by product type and currency. It fetches RSC search responses, extracts initialProductsList, filters configured products by configured currencies, tracks state in state.json, and sends Telegram notifications for new and disappeared offers.
bsv_tracker/config.py: environment-based runtime configuration.bsv_tracker/models.py:Productdataclass and state serialization helpers.bsv_tracker/parser.py: safe extraction and JSON parsing ofinitialProductsListfrom the RSC response.bsv_tracker/state.py: state loading and atomic state saving.bsv_tracker/telegram.py: TelegramsendMessageclient with retries.bsv_tracker/monitor.py: fetch, parse, diff, notify, and save workflow.bsv_tracker/state.json: local runtime state file. No external database is used.bsv_tracker/state.example.json: tracked empty state template.
CURRENCIES: comma-separated currency markers expected in product names, for exampleNGN,TRY,USD.PRODUCTS: comma-separated BuySellVouchers product type slugs, for examplegift-cards-apple,Gift_cards-Steam_Gift_Cards.
Take product type slugs from BuySellVouchers URLs:
https://www.buysellvouchers.com/en/products/view/<product-type>/<encoded-id>/
The state file stores the latest known products keyed by encoded_id. Runtime state.json is intentionally ignored by git because it changes after each monitor run.
On each run:
- Load previous products from
state.json. - Fetch and parse current configured product types for each configured currency.
- Compare previous
encoded_idvalues with currentencoded_idvalues. - Send notifications for new IDs and removed IDs.
- Save the current product snapshot back to
state.json.
The snapshot includes product details so removed-product notifications can still include name, seller, and URL after the offer disappears from the search response.
Create a virtual environment and install dependencies:
python3.12 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txtSet environment variables:
export BSV_SEARCH_URL_TEMPLATE='https://www.buysellvouchers.com/en/products/list/?S={currency}'
export CURRENCIES='NGN,TRY,USD'
export PRODUCTS='gift-cards-apple,Gift_cards-Steam_Gift_Cards'
export TELEGRAM_BOT_TOKEN='your-bot-token'
export TELEGRAM_CHAT_ID='your-chat-id'Run once:
python -m bsv_tracker.monitorOptional configuration:
export BSV_STATE_FILE='bsv_tracker/state.json'
export BSV_REQUEST_TIMEOUT='30'
export BSV_REQUEST_RETRIES='3'
export BSV_RETRY_BACKOFF='2'
export LOG_LEVEL='INFO'Example: run every 5 minutes.
*/5 * * * * cd /opt/bsv_tracker && TELEGRAM_BOT_TOKEN='your-bot-token' TELEGRAM_CHAT_ID='your-chat-id' CURRENCIES='NGN,TRY,USD' PRODUCTS='gift-cards-apple,Gift_cards-Steam_Gift_Cards' /opt/bsv_tracker/.venv/bin/python -m bsv_tracker.monitor >> /var/log/bsv_tracker.log 2>&1Use an absolute project path and absolute Python path. Cron has a minimal environment.
Create a dedicated system user:
sudo useradd --system --create-home --home-dir /opt/bsv_tracker --shell /usr/sbin/nologin bsv_trackerClone the repository under /opt/bsv_tracker, install dependencies, and create /opt/bsv_tracker/.env from .env.example.
sudo git clone https://github.com/oomchiller/bsv_tracker.git /opt/bsv_tracker
sudo chown -R bsv_tracker:bsv_tracker /opt/bsv_tracker
sudo runuser -u bsv_tracker -- python3.12 -m venv /opt/bsv_tracker/.venv
sudo runuser -u bsv_tracker -- /opt/bsv_tracker/.venv/bin/pip install -r /opt/bsv_tracker/requirements.txt
sudo cp /opt/bsv_tracker/.env.example /opt/bsv_tracker/.env
sudo cp /opt/bsv_tracker/bsv_tracker/state.example.json /opt/bsv_tracker/bsv_tracker/state.json
sudo chmod 600 /opt/bsv_tracker/.env
sudo chown bsv_tracker:bsv_tracker /opt/bsv_tracker/.envConfigure at least:
BSV_SEARCH_URL_TEMPLATE=https://www.buysellvouchers.com/en/products/list/?S={currency}
CURRENCIES=NGN,TRY,USD
PRODUCTS=gift-cards-apple,Gift_cards-Steam_Gift_Cards
TELEGRAM_BOT_TOKEN=your-bot-token
TELEGRAM_CHAT_ID=your-chat-id
BSV_STATE_FILE=/opt/bsv_tracker/bsv_tracker/state.jsonCreate /etc/systemd/system/bsv_tracker.service:
[Unit]
Description=BuySellVouchers offer tracker
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
User=bsv_tracker
Group=bsv_tracker
WorkingDirectory=/opt/bsv_tracker
EnvironmentFile=/opt/bsv_tracker/.env
ExecStart=/opt/bsv_tracker/.venv/bin/python -m bsv_tracker.monitorCreate /etc/systemd/system/bsv_tracker.timer:
[Unit]
Description=Run BuySellVouchers offer tracker every 5 minutes
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
Unit=bsv_tracker.service
[Install]
WantedBy=timers.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl start bsv_tracker.service
sudo systemctl enable --now bsv_tracker.timer
systemctl list-timers bsv_tracker.timerCheck logs:
journalctl -u bsv_tracker.service -n 100 --no-pagerManual run:
sudo runuser -u bsv_tracker -- bash -lc 'set -a; . /opt/bsv_tracker/.env; set +a; cd /opt/bsv_tracker; .venv/bin/python -m bsv_tracker.monitor'Reset state and resend all currently available matching offers:
sudo systemctl stop bsv_tracker.timer
sudo runuser -u bsv_tracker -- tee /opt/bsv_tracker/bsv_tracker/state.json >/dev/null <<'EOF'
{
"products": {}
}
EOF
sudo systemctl start bsv_tracker.service
sudo systemctl start bsv_tracker.timerUpdate an existing server checkout:
sudo systemctl stop bsv_tracker.timer
cd /opt/bsv_tracker
sudo -u bsv_tracker git pull --ff-only
sudo runuser -u bsv_tracker -- /opt/bsv_tracker/.venv/bin/pip install -r /opt/bsv_tracker/requirements.txt
sudo systemctl start bsv_tracker.service
sudo systemctl start bsv_tracker.timer