Most GPU hosts set a price once, when they add a machine, and never touch it again. That price is wrong most of the time. While the machine sits idle it is too high: a renter looking at the list picked something cheaper. When the machine is re-rented minutes after the last renter left, it is too low: someone was waiting, and would have paid more.
On Paralon you can now change a node's price from code, through the provider API. This guide uses that to let each node's price follow its own demand, inside limits you choose, so you stop guessing.
The rule
For each node, every 15 minutes:
| What happened | What the script does |
|---|---|
| On the market and idle for 6 hours since the last change | lowers the price by 5% |
| Rented again within 1 hour of the previous rental ending | raises the price by 5% for the next rental |
| Anything else | keeps the price |
Two limits wrap the rule. The price never goes below 80% or above 150% of the node's default price (your floor and ceiling, both settable), and never outside what Paralon allows: 50% to 300% of the default, which the API reports per node as price.min and price.max. Spot nodes rent at the spot price and are left alone.
Why the node's own demand and not the market's: it is the signal that belongs to you. Two cards of the same model can rent at different prices because of where they are, their reputation or their uptime record. An idle machine says its price is too high for what it offers; a queue of renters says the opposite.
What you need
- A Paralon API key with the My nodes permission (Console → API keys).
- Python 3.8 or newer with
requests.
Both scripts are in the auto-pricing/ folder of our open-source provider tools repository (MIT).
The two calls it uses
Read every node, with its state and its price limits:
curl https://paraloncloud.com/api/v1/nodes -H "Authorization: Bearer $PARALON_API_KEY"
"price": { "currency": "USD", "unit": "hour", "spot": false,
"default": 0.54, "min": 0.27, "max": 1.62,
"custom": null, "renter_pays": 0.54 }
Set a price (or null to go back to the default):
curl -X PATCH https://paraloncloud.com/api/v1/nodes/$NODE_ID \
-H "Authorization: Bearer $PARALON_API_KEY" -H "Content-Type: application/json" \
-d '{"price_per_hour": 0.51}'
The price is what a renter pays per hour for the whole node, in US dollars; you earn it minus the platform fee. A price outside min–max is refused with the range in the message, and a rental already running keeps the price it started at.
The decision, in one function
The API reports a node's current state, not its history, so the script remembers two times per node in a small JSON file: when it became idle, and when its last rental ended. decide() takes the node and that memory and returns the new price, or none:
if state == "rented":
if prev != "rented": # a rental just started
quick = last_rental_end is not None and now - last_rental_end <= QUICK_HOURS * 3600
if quick and current < hi:
return round(min(hi, current * (1 + STEP)), 2) # renters were waiting
return None # rented: keep
if state == "available":
idle_h = (now - idle_since) / 3600
if idle_h >= IDLE_HOURS and current > lo:
idle_since = now # a full IDLE_HOURS before the next step
return round(max(lo, current * (1 - STEP)), 2) # nobody wants it at this price
Offline, paused and not-yet-ready nodes are not on the market, so their idle time does not count: a machine that was switched off for a night does not come back cheaper.
A week of one RTX 4090, replayed
simulate.py feeds a made-up week of one node through the same decide() with the defaults, and makes no API call. The node starts at its $0.54 default, sits idle for most of a day, then gets rented in quick succession, then idles again:
h 0 available $0.54 available, idle 0.0 h: keep
h 6 available $0.54 -> $0.51 idle 6.0 h: -5%
h 12 available $0.51 -> $0.48 idle 6.0 h: -5%
h 18 available $0.48 -> $0.46 idle 6.0 h: -5%
h 19 rented $0.46 rented: keep
h 31 available $0.46 available, idle 0.0 h: keep
h 31.5 rented $0.46 -> $0.48 re-rented within 1 h: +5% for the next rental
h 55 available $0.48 available, idle 0.0 h: keep
h 55.5 rented $0.48 -> $0.50 re-rented within 1 h: +5% for the next rental
h 86 available $0.50 -> $0.47 idle 6.0 h: -5%
h 92 available $0.47 -> $0.45 idle 6.0 h: -5%
h 98 available $0.45 -> $0.44 idle 6.0 h: -5%
h 104 available $0.44 available, idle 6.0 h: keep
Three things to read from it. A day of idling took the price down 15% before a renter took it at $0.46. Two quick re-rentals moved it back up, each change applying to the next rental, never to the one that just started. And at the end the price stopped at $0.44, the floor (80% of $0.54, rounded up to the cent), however long the node keeps idling.
Run it
Always start with a dry run. It reads your nodes and prints what it would do, without changing anything:
pip install requests
export PARALON_API_KEY=prlc_your_key
python3 auto_price.py --dry-run
On our own account, with our RTX 4090 rented and the other machines offline, it decided to touch nothing, which is right (the 4090's line):
21:49:36 4090 rented $0.54/h rented: keep
Then run it for real, as a service (systemd or a restart: unless-stopped container). It checks every 15 minutes, logs every decision with its reason, and keeps its memory in auto_price_state.json next to it:
python3 auto_price.py
The knobs
| Variable | Default | What it sets |
|---|---|---|
IDLE_HOURS | 6 | idle time on the market before a step down |
QUICK_HOURS | 1 | how soon after a rental a new one counts as demand |
STEP | 0.05 | size of each change |
FLOOR | 0.8 | lowest price, as a share of the default |
CEILING | 1.5 | highest price, as a share of the default |
MARKET_JSON | none | a file of reference prices per GPU model; the price then stays within MARKET_BAND (15%) of it |
CHECK_MINUTES | 15 | how often it checks |
Keep the steps small and the floor honest. A price that drops fast fills the machine with renters who leave when it goes back up; one that never drops below your electricity cost is the only floor that matters. Count your power at full load: a 4090 drew about 450 W in our measurements.
For a fleet
The script handles every node of the account in one pass: one GET /nodes, and one PATCH only for the nodes whose price changes. Machines with different GPUs get their own default, limits and steps automatically. If you also list machines on another marketplace, run the multi-marketplace watcher next to it: the two never fight, because one changes availability and the other changes the price.
The provider API docs list every field a node returns.
Frequently asked questions
Does changing the price affect a rental that is already running?
No. A rental keeps the price it started with until it ends. A new price applies to the next rental.
What limits does Paralon put on a custom price?
Between 50% and 300% of the default price for the node's GPUs. The API reports both limits for each node (price.min and price.max) and refuses a price outside them. The script adds your own, narrower floor and ceiling inside that range.
Does the script look at other providers' prices?
Not by default: it follows the node's own demand, which is the signal you actually control. If you trust a reference price for a GPU model (yours from another marketplace, for example), put it in MARKET_JSON and the script keeps the price within 15% of it.
Does it work on spot nodes?
No. A spot node always rents at the default price minus the spot discount and takes no custom price, so the script leaves spot nodes alone.
How do I try it without changing anything?
Run it with --dry-run: it reads your nodes and prints what it would do, without a single change. simulate.py replays a made-up week through the same rule and makes no API call at all.



