← All guides
pricingbillingephemeral computeautomation

How Much Does a Disposable VM Cost? A Per-Minute Billing Estimator for Batch Workloads

LiteVPS bills disposable VMs per minute at price_hourly / 60, caps each VM at its monthly price, and keeps charging while a VM is stopped. This article includes a tested estimator script for pricing a single sandbox or a whole batch.

Published · LiteVPS Engineering

A disposable VM on LiteVPS costs its plan's hourly price divided by 60 for every minute it exists, including minutes spent stopped. The monthly price on the pricing page is a per-VM cap for a calendar month, not a flat subscription, so a VM that lives a few minutes costs only those minutes. Creating a VM requires a prepaid balance of at least $1.00 and sets aside the estimated first-hour cost at create time, which is returned only if provisioning fails. Destroying the VM, or letting its TTL expire, stops the meter. The estimator below reproduces these numbers exactly.

What does the meter actually charge?

Per-minute metering comes from the plan's hourly price divided by 60. The following numbers are the live public plans as of August 10, 2026, from GET /api/pricing:

Plan vCPU RAM Disk $/hour $/minute $/month cap
Lite1 1 1 GB 20 GB $0.01 $0.000167 $7.30
Medium1 2 2 GB 25 GB $0.02 $0.000333 $14.60
Performance1 4 8 GB 30 GB $0.05 $0.000833 $36.50

Attaching a public IPv4 adds $0.00274/hour (cap $2.00/month) to both the metered rate and the create-time reservation. The per-minute figures above are price_hourly / 60, matching the meter's calculation of (price_hourly / 60) × minutes.

Three behaviors decide most of what a disposable VM actually costs:

  • Running and stopped VMs both accrue. A stopped VM still holds its disk and a reserved slot on the host, so it keeps metering until it is destroyed.
  • Destroying stops the meter. Deleting the VM (or letting its server-side TTL expire) bills any accrued-but-not-yet-flushed minutes and then stops charging. Billing is accumulated per minute and written to your balance about every ten minutes; each day's usage is rolled up into a single ledger entry.
  • The monthly price is a cap. Once a VM has accrued its monthly price within a calendar month, charges stop for that VM and reset on the first of the next month. A VM that lives the full month never costs more than the monthly figure.

The create-time costs that are easy to miss

The per-minute rate is only part of the picture. When the API provisions a VM it also:

  • Requires a minimum prepaid balance of $1.00. The create call returns HTTP 402 when the balance is below that.
  • Sets aside the estimated first-hour cost at create. That is the plan's hourly price (floor $0.001) plus the public IPv4 add-on if requested, deducted after placement is validated. It is returned only if provisioning fails. Budget roughly one hour's cost per VM, on top of the metered usage.
  • Checks per-account limits. Accounts start with a limit of one concurrent VM; batch and parallel use requires raising that limit. A batch create call is also capped by the max_batch_size setting, which defaults to 10.

Every authenticated response includes an X-Balance-Remaining header, so an agent can watch the meter after each API call without polling GET /api/billing/balance.

A tested estimator

The script below reproduces the meter: per-minute rate, the monthly cap, the running-plus-stopped accumulation, and the create-time reservation. It is dependency-free (Python 3 standard library only) and hardcodes the live prices above so you can check it against the current GET /api/pricing response.

#!/usr/bin/env python3
"""Estimate the cost of a disposable VM (or a batch of them) on LiteVPS.

Billing model, verified against https://api.litevps.dev/api/pricing and the
LiteVPS billing implementation:

  * Usage is metered per minute at price_hourly / 60.
  * The monthly price is a per-VM cap on what one VM can accrue in a calendar
    month. A VM that lives the whole month is capped at the monthly price.
  * VMs in "running" OR "stopped" state keep accruing. Destroy the VM (or let
    its TTL expire) to stop billing; the last partial minutes are billed when
    the VM is destroyed.
  * Creating a VM requires a prepaid balance of at least $1.00 and sets aside
    the estimated first-hour cost at create time (price_hourly, floor $0.001,
    plus the public IPv4 add-on if requested). That amount is returned only if
    provisioning fails.

Run `python3 estimate_disposable_vm_cost.py --selftest` to check the numbers
against the assertions below.
"""

import argparse
import sys

PLANS = {
    # slug: (price hourly USD, price monthly USD)  — live GET /api/pricing
    "lite1": (0.01, 7.30),
    "medium1": (0.02, 14.60),
    "performance1": (0.05, 36.50),
}

PUBLIC_IPV4_HOURLY = 0.00274  # add-on, USD/hour
PUBLIC_IPV4_MONTHLY = 2.00    # add-on, USD/month cap
MIN_CREATE_BALANCE = 1.00     # USD — required before the platform provisions
RESERVATION_FLOOR = 0.001     # USD — minimum first-hour estimate set aside


def per_minute(hourly):
    return hourly / 60.0


def metered_cost(hourly, monthly, minutes):
    """Metered USD for one VM that lived `minutes` in the current calendar month."""
    raw = per_minute(hourly) * minutes
    if monthly > 0:
        return min(raw, monthly)
    return raw


def reservation(hourly, ipv4):
    """USD set aside at create (estimated first-hour cost, add-on included)."""
    est = max(hourly, RESERVATION_FLOOR)
    if ipv4:
        est += PUBLIC_IPV4_HOURLY
    return est


def min_balance_for(vms, reservations_per_vm):
    """Smallest prepaid balance that passes the API's create checks."""
    return max(MIN_CREATE_BALANCE, vms * reservations_per_vm)


def estimate(plan, minutes, vms=1, stopped_minutes=0, ipv4=False,
             monthly_charged=0.0):
    hourly, monthly = PLANS[plan]
    rate = per_minute(hourly)
    total_minutes = minutes + stopped_minutes

    acc = 0.0
    for _ in range(vms):
        raw = rate * total_minutes
        remaining = max(monthly - monthly_charged, 0.0)
        acc += min(raw, remaining)
    metered = acc

    reserv = reservation(hourly, ipv4)
    reservations_total = reserv * vms
    balance_impact = metered + reservations_total
    needed = min_balance_for(vms, reserv)

    return {
        "plan": plan,
        "hourly": hourly,
        "monthly_cap": monthly,
        "per_minute": rate,
        "reservation_per_vm": reserv,
        "vms": vms,
        "runtime_minutes": minutes,
        "stopped_minutes": stopped_minutes,
        "metered": metered,
        "reservations_total": reservations_total,
        "balance_impact": balance_impact,
        "min_balance_to_create": needed,
        "ipv4": ipv4,
    }


def render(r):
    line = (
        f"{r['plan']}: {r['per_minute']:.6f} $/min "
        f"({r['hourly']:.4f} $/h, cap {r['monthly_cap']:.2f} $/month)"
    )
    print(line)
    print(f"  VMs: {r['vms']} x {r['runtime_minutes']}m runtime"
          f" + {r['stopped_minutes']}m stopped"
          + (" + public IPv4 add-on" if r["ipv4"] else ""))
    print(f"  set aside at create: {r['reservation_per_vm']:.4f} $/VM"
          f" x {r['vms']} = {r['reservations_total']:.4f} $")
    print(f"  metered usage: {r['metered']:.4f} $")
    print(f"  total balance impact: {r['balance_impact']:.4f} $")
    print(f"  minimum prepaid balance to create: {r['min_balance_to_create']:.2f} $")


def selftest():
    def close(a, b, tol=1e-6):
        assert abs(a - b) < tol, f"{a} != {b}"

    # Per-minute rate on Lite1 is $0.01 / 60.
    close(per_minute(0.01), 0.01 / 60.0)
    # 60 minutes on Lite1 meters exactly $0.01.
    close(metered_cost(0.01, 7.30, 60), 0.01)
    # 100000 minutes (~69 days) would meter $16.67, but is capped at $7.30.
    close(metered_cost(0.01, 7.30, 100000), 7.30)
    # No cap -> no limit (cap 0 disables it).
    close(metered_cost(0.01, 0, 100000), 100000 * (0.01 / 60.0))
    # Reservation is the hourly price (floor $0.001).
    close(reservation(0.01, False), 0.01)
    close(reservation(0.001, False), 0.001)
    # Public IPv4 add-on raises both the metered rate and the reservation.
    close(per_minute(0.01 + PUBLIC_IPV4_HOURLY), (0.01274) / 60.0)
    close(reservation(0.01, True), 0.01274)
    # A 30-minute batch of 3 Lite1 VMs.
    r = estimate("lite1", minutes=30, vms=3)
    close(r["metered"], 3 * (0.01 / 60.0) * 30)  # 0.015
    close(r["reservations_total"], 0.03)
    close(r["balance_impact"], 0.045)
    # 60m running + 30m stopped meters the same as 90m running.
    close(estimate("lite1", minutes=60, stopped_minutes=30)["metered"],
          estimate("lite1", minutes=90)["metered"])
    # Cap applies per calendar month; prior charges reduce the remaining cap.
    close(metered_cost(0.01, 7.30, 43800) - metered_cost(0.01, 7.30, 30000),
          metered_cost(0.01, 7.30, 13800))
    close(estimate("lite1", minutes=100000, monthly_charged=0.0)["metered"], 7.30)
    # Minimum create balance is at least $1.00 and covers all reservations.
    close(min_balance_for(1, 0.01), 1.00)
    close(min_balance_for(3, 0.01), 1.00)
    close(min_balance_for(300, 0.01), 3.00)
    print("selftest: all assertions passed")


def main(argv):
    parser = argparse.ArgumentParser(
        description="Estimate the cost of disposable VMs on LiteVPS.")
    parser.add_argument("--plan", choices=sorted(PLANS), default="lite1")
    parser.add_argument("--minutes", type=int, default=60,
                        help="runtime minutes per VM")
    parser.add_argument("--vms", type=int, default=1)
    parser.add_argument("--stopped-minutes", type=int, default=0,
                        help="minutes each VM exists while stopped (still billed)")
    parser.add_argument("--ipv4", action="store_true",
                        help="attach the public IPv4 add-on")
    parser.add_argument("--monthly-charged", type=float, default=0.0,
                        help="already-charged usage this calendar month per VM")
    parser.add_argument("--selftest", action="store_true")
    args = parser.parse_args(argv)

    if args.selftest:
        selftest()
        return 0

    render(estimate(args.plan, args.minutes, vms=args.vms,
                    stopped_minutes=args.stopped_minutes, ipv4=args.ipv4,
                    monthly_charged=args.monthly_charged))
    return 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))

Run the self-test to confirm the assertions still hold for your copy, then estimate a workload:

python3 estimate_disposable_vm_cost.py --selftest
python3 estimate_disposable_vm_cost.py --plan lite1 --minutes 30 --vms 3

Output for the batch example:

lite1: 0.000167 $/min (0.0100 $/h, cap 7.30 $/month)
  VMs: 3 x 30m runtime + 0m stopped
  set aside at create: 0.0100 $/VM x 3 = 0.0300 $
  metered usage: 0.0150 $
  total balance impact: 0.0450 $
  minimum prepaid balance to create: 1.00 $

The batch example assumes your account's per-VM limit and max_batch_size allow three VMs; both defaults start lower for new accounts.

Worked examples

Scenario Set aside at create Metered Balance impact Minimum balance
1 × Lite1 for 30 minutes $0.01 $0.005 $0.015 $1.00
1 × Medium1, 45 min, public IPv4 $0.0227 $0.015 $0.0377 $1.00
1 × Performance1 for 2 hours $0.05 $0.10 $0.15 $1.00
1 × Lite1 for a full month $0.01 $7.30 $7.31 $1.00

The last row shows the cap at work: a whole month of metering never exceeds the monthly figure, so the reservation is the only thing pushing the month slightly past the listed $7.30.

When should you use this estimator?

  • Budgeting disposable batch jobs, integration tests, or temporary sandboxes before you run them.
  • Comparing the cost of a short-lived VM against a container or a serverless function for the same task.
  • Planning batch runs, where the per-VM reservation multiplies and the create call checks your $1.00 minimum and per-account limit.

When should you not use this estimator?

  • For always-on workloads. Once a VM crosses roughly a month of uptime the cap applies and the monthly price is the number that matters.
  • As a substitute for the live pricing endpoint. Prices and limits can change; re-check GET /api/pricing and the max_batch_size and per-account limit settings before relying on exact figures.
  • It models compute minutes, the public IPv4 add-on, and the create-time reservation only. It does not include other products such as snapshots.

A safe lifecycle pattern for ephemeral compute shows the create-wait-work-delete controller this estimator pairs with. How to give an AI agent a disposable Linux sandbox covers the isolation boundary, and VPS, container, or serverless function for agent code execution? helps decide whether a VM is warranted at all. See the LiteVPS platform guide and API reference for the create, TTL, and billing endpoints.

Methodology note

The per-minute formula, monthly cap, running-and-stopped accrual, delete-time billing flush, $1.00 minimum balance, create-time first-hour reservation with refund on provisioning failure, default max_batch_size of 10, per-account VM limit default of 1, and X-Balance-Remaining header were checked against the LiteVPS implementation on August 10, 2026. Plan prices were read from the live GET /api/pricing endpoint on the same date and may change.