Two tools built on our data, and what our docs left out
Products with no monthly price. billing_cycles lists only the terms a product is sold on. Seven products, all of them special offers, have no monthly key at all. PulseWatch showed a dash for them and recorded no price history, so their price moves were invisible.
Two prices for one product. PulseWatch also compares the feed with the storefront once a day, and for some products the store’s “Starting from” price was higher than the feed’s price. Its README put that down to “a stale monthly price in the feed”. The real reason is that the store adds the cheapest of a product’s required options to its “Starting from” price, while the feed publishes the base price. Both are correct. They answer different questions.
None of these is a bug on either side. Each one is a field whose meaning lived in our code and nowhere else. The product-feed items on this list are now written down on the feeds page.
How to poll a host’s feed politely
PulseWatch fetches the catalog every five minutes. Our product feed is rebuilt every 15 minutes, so two of every three fetches download a file that has not changed. That costs the client and the server bandwidth for nothing, and it is fixable with headers that are already there.
Pulsed Media’s feed responses carry ETag and Last-Modified. Send them back and you get an empty 304 Not Modified when nothing changed:
url=https://pulsedmedia.com/data/v1/products.json etag=$(curl -sI "$url" | awk -F': ' 'tolower($1)=="etag"{print $2}' | tr -d '\r') curl -s -o /dev/null -w '%{http_code}\n' -H "If-None-Match: $etag" "$url" # 304
In a Python client the same thing takes a few lines with the standard library:
import json, urllib.request, urllib.error def fetch(url, cache): req = urllib.request.Request(url) if cache.get("etag"): req.add_header("If-None-Match", cache["etag"]) try: with urllib.request.urlopen(req, timeout=30) as r: cache.update(etag=r.headers.get("ETag"), body=r.read()) except urllib.error.HTTPError as e: if e.code != 304: raise return json.loads(cache["body"])
Three more habits that hold for any host’s feed, not just ours:
- Check the timestamp, not just the status code. Our feeds carry
generated_at. A 200 with a feed that is three hours old means the generator stopped, and a monitor should say “stale” instead of reporting old stock as current. The same goes for a cached copy you fall back to when a fetch fails. - Poll at the rebuild rate, not faster. If the docs say the data refreshes every 15 minutes, a five-minute poll with conditional requests is fine and a one-minute poll without them is noise.
- Treat unknown fields as unknown. When a value looks odd, like a negative stock, ask or read the docs before you give it a meaning. A guess shown on a public page becomes a fact for whoever reads it.
One store-specific tip, because PulseWatch sends visitors to our store with a referral id: our aff.php?aff=ID&pid=N link sets the referral and then lands on that product’s order form, so a referral link can go straight to the product. A plain ?aff= added to a store page does nothing.
Local tools, public tunnels
PulseWatch can publish itself on a Cloudflare quick tunnel, so the dashboard you run on a home server gets a public HTTPS address in one command. That is convenient, and it changes what the code has to defend against. A page that only you open on 127.0.0.1 now faces anyone who finds the address, and even on 127.0.0.1, a web page open in your browser may be able to send it requests.
Two defects came from that shift, and both are common in small self-hosted tools:
- Query values echoed into links without escaping. Most of PulseWatch escapes its HTML carefully, and the pages showed it. One helper built pager links from the raw query string, though, so a crafted catalog URL could run script in the page.
- An expensive action behind a plain GET. The daily feed-versus-storefront check could be started by anyone with
?run=1, with no token and no cooldown. Every call made the instance fetch the feeds and eight store pages from its owner’s IP.
The fixes are short: URL-encode and escape every value that goes into an attribute, and put anything that costs requests behind the same token and cooldown as the manual scan. Both are in the pull request we sent, alongside the feed-meaning fixes above. As I write this, on 20 October 2026, it is open. Until those fixes are in the version you run, skip the tunnel and don’t open PulseWatch links that other people send you.
We didn’t run any of the code to find these. A repository from outside is untrusted input for us, so the review was reading only, and the fixes were tested by the project’s own CI on our fork.
Why a host fixes other people’s tools
At Pulsed Media we run our own hardware and our own open-source platform, PMSS. Publishing feeds and an API is part of the same idea: what you rent from us is yours to script, watch and build on. When someone does, the cheapest help we can give is a careful read and a pull request, plus the line in our docs that would have saved them the guess.
For anyone who publishes data that other people build on:
- Write down what each field means, not only its name and type. Units, rounding, null, and what a strange value such as a negative number stands for.
- Say how fresh the data is and send validators. A refresh interval, a
generated_at, andETag/Last-Modifiedlet clients be polite for free. - Read the tools people build on you. Their models of your data show you exactly where your docs are silent.
Both tools have pages on our wiki: PMSS Fleet Manager and PulseWatch, with setup notes and what to watch out for.
If you build on a host’s API or feeds, or you’d like a host that reads the code people build on it, I run support and infrastructure at Pulsed Media. Seedboxes and storage boxes on our own hardware in our own datacenters in Finland, an open-source platform, 1Gbps or 10Gbps, EU jurisdiction, 14-day money-back. Customers earn AI credits from the services they pay for.
Fuente: Artículo original