Products
Read the Proxio catalog and live pricing with GET /products, including per-GB residential rates with volume tiers and per-IP-per-day ISP and datacenter pricing with duration discounts. ETag / If-None-Match give you a cheap 304 when pricing hasn't changed.
GET /products returns the current catalog and pricing: what you can buy and
what it costs, right now. Use it to build a pricing screen or to compute an order
total before you place one.
Scope: read
List products
curl https://dashboard.proxio.net/api/v1/products \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.get(
f"{BASE}/products",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=15,
)
resp.raise_for_status()
for product in resp.json()["data"]["products"]:
print(product["category"], product["billing"])const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/products`, {
headers: { Authorization: `Bearer ${API_KEY}` },
})
const { data } = await res.json()
for (const product of data.products) {
console.log(product.category, product.billing)
}200 response:
{
"data": {
"products": [
{
"category": "RESIDENTIAL",
"billing": "per_gb",
"currency": "USD",
"price_per_gb": "2.50",
"ips_per_gb": 0,
"unlimited_supported": true,
"volume_tiers": [
{ "min_gb": 0, "percent_off": "0.00", "price_per_gb": "2.50" },
{ "min_gb": 50, "percent_off": "10.00", "price_per_gb": "2.25" }
],
"renewal": { "auto": true }
},
{
"category": "ISP",
"billing": "per_ip_duration",
"currency": "USD",
"base_day_rate": "1.20",
"duration_discounts": {
"1": 0, "7": 0, "14": 0.05, "30": 0.20, "60": 0.30, "90": 0.40
},
"allowed_days": [1, 7, 14, 30, 60, 90]
}
]
},
"meta": { "request_id": "req_8Ke2jP4mQ" }
}Billing models
A product's billing field tells you how it's priced.
per_gb (residential)
Metered by bandwidth. price_per_gb is the base rate, and volume_tiers lists
the discounts that kick in at higher volumes. Each tier gives its min_gb
threshold, the percent_off, and the resulting price_per_gb. When
unlimited_supported is true, the category can also be sold as an
unlimited-bandwidth package.
A residential service isn't manually extended, which is what the
RESIDENTIAL product's "renewal": { "auto": true } reflects. Continuity comes
from auto-renewal instead: each cycle
renews automatically at the current price_per_gb / volume_tiers rates for
the plan's GB allotment. Use topup to add data to
a residential service right now. ISP and datacenter products carry no
renewal field: they're extended manually instead, see per_ip_duration
below.
per_ip_duration (ISP and datacenter)
Priced per IP per day. base_day_rate is the daily rate for one IP, and
duration_discounts maps a rental length in days to a discount, so longer
rentals cost less per day. allowed_days lists the durations you can buy, which
are the valid values for days when you place an order.
Discounts are fractions, not percentages
Every value in duration_discounts is a fraction between 0 and 1, not a
percentage. 0.20 means 20% off, 0 means no discount. Multiplying by a
value you read as a percentage will overstate the price by 100x.
allowed_days is derived from the keys of duration_discounts, so the two
always agree: a day count that isn't a key is not purchasable.
Compute an ISP or datacenter total like this:
total = base_day_rate × days × (1 − duration_discounts[days]) × ip_quantitySo 3 IPs for 30 days at a base_day_rate of 1.20 with a "30" discount of
0.20 costs 1.20 × 30 × 0.80 × 3 = 86.40. The per-IP subtotal is rounded to
2 decimals before it is multiplied by ip_quantity.
Prices are strings
Every price is a decimal string ("2.50"), never a float. Compute totals
with a decimal type to avoid rounding drift. The duration_discounts values
are the one exception: they are JSON numbers.
When you're ready to buy, server-side pricing is always authoritative, any prices you send in an order body are ignored. See Orders.
Caching
Unlike the locations catalog, pricing sets
Cache-Control: private, no-cache: store the response, but revalidate it on
every reuse rather than serving a stale price for up to an hour, prices
change more often than the geo catalog and a client polling for a price
change wants to know within seconds, not up to 3600 of them.
Every response also carries an ETag. Paired with no-cache, that
revalidation is cheap: send the ETag back as If-None-Match and an
unchanged catalog answers 304 Not Modified with no body, so a poller pays
for a header round trip instead of the full product list on every check.
curl -si https://dashboard.proxio.net/api/v1/products \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x" \
-H 'If-None-Match: W/"c2FsdGVkX1+3Qz..."'
# HTTP/1.1 304 Not ModifiedRelated pages
API Keys
Manage Proxio API keys programmatically with GET/POST /api-keys and DELETE /api-keys/{id}. A key can only mint a key that is weaker than or equal to itself, the plaintext token is returned exactly once, and expiry, rate limit, and IP allowlist all clamp to the calling key's own values.
Services
List your Proxio services and read connection info with GET /services and GET /services/{id}, and toggle auto-renewal with PATCH /services/{id}. A service is a package, residential services return a gateway endpoint and credential, static services return a fixed proxy list.

