ProxioDocs
API Reference

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_quantity

So 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 Modified

On this page