Pricing your residential resale: undercut retail, keep 40%
2026-10-21 · Bazyl

A resale ladder is built from the top down. Our two public per-gigabyte lines are your ceiling at every size, your wholesale cost sets the floor, and the packs sit between them, closer to the floor as they get bigger. The margin math post showed where the margin leaks; this one is the construction, and it ends with a script that prints a ladder for whatever your cost turns out to be.
The mistake is building from cost up with one flat markup. Double $0.50 and every pack is $1.00 per GB: the 1 GB pack leaves three dollars on the table against retail, and the 1,000 GB pack sits above our own subscription line, so the one buyer who compares prices walks.
Two ceilings, and the lower one wins at every size
Anyone can read our prices, so at each pack size your ceiling is the lower of the two public lines. Pay as you go, per GB in US dollars, as of 25 September 2026 and unchanged when re-read on 1 October:
- 1 GB: $4.20
- 2 to 4 GB: $3.90
- 5 to 14 GB: $3.60
- 15 to 29 GB: $3.00
- 30 to 49 GB: $1.92
- 50 to 99 GB: $1.68
- 100 to 199 GB: $1.20
- 200 to 499 GB: $1.14
- 500 to 999 GB: $1.08
- 1,000 GB and up: $0.96
Subscription, per GB, same date. Plans come in 10, 25, 50, 100, 250, 500, 1,000 and 2,000 GB:
- 5 to 14 GB: $2.82
- 15 to 29 GB: $2.40
- 30 to 49 GB: $1.54
- 50 to 99 GB: $1.34
- 100 to 199 GB: $1.02
- 200 to 499 GB: $0.99
- 500 to 999 GB: $0.96
- 1,000 GB and up: $0.90
The subscription line is lower wherever it exists, and a subscriber compares you against it, not against pay as you go. Below 5 GB there is no subscription band, so pay as you go is the only ceiling there. Price under the subscription line and you are under both.
Charge in euros and the lines are these, as of 1 October 2026. Pay as you go: €3.50 at 1 GB, €3.25 at 2 to 4, €3.00 at 5 to 14, €2.50 at 15 to 29, €1.60 at 30 to 49, €1.40 at 50 to 99, €1.00 at 100 to 199, €0.95 at 200 to 499, €0.90 at 500 to 999, €0.80 from 1,000. Subscription: €2.35 at 5 to 14, €2.00 at 15 to 29, €1.28 at 30 to 49, €1.12 at 50 to 99, €0.85 at 100 to 199, €0.83 at 200 to 499, €0.80 at 500 to 999, €0.75 from 1,000.
Use the line for the currency you charge in. The live ladder for all four currencies is on the pricing page.
The floor is your cost divided by 0.6
A 40% gross margin means cost is 60% of price, so the lowest price you ever print is cost divided by 0.6. Wholesale starts at $0.50 per GB; the exact band depends on your volume and I quote it on request, which is why the script takes the cost as an input instead of assuming one.
At $0.50 the floor is $0.84 per GB, rounded up so the margin never dips under 40%. Against the $0.90 subscription line at 1,000 GB that leaves six cents of room at the top of the ladder: enough to be visibly under us, not enough to be generous. That is the point of putting the floor at the top. The big buyer is the one comparing, and 40% of a big pack is still more money than 80% of a small one.
The small packs run higher on their own. At 1 GB the ceiling is $4.20 and the floor $0.84, so the same 10% undercut lands near $3.78, and the script's rounded $3.50 pack still keeps 86%. Nobody buying 1 GB compares lines to the cent; they're buying a first try.
Three facts about the floor's other side. A partner's first order is 100 GB and any size after that (week one walks through what happens to them); pool gigabytes never expire; there is no monthly fee and no branding fee, so the ladder is the whole cost model. Wholesale is paid by bank transfer, and every sale is invoiced.
Pick pack sizes your buyers already know
Mirror our plan sizes and the comparison is one-to-one. 10, 25, 50, 100, 250, 500 and 1,000 GB are sizes a buyer has already seen on our page, so your price against ours is a single glance. Add a 1 GB or 5 GB entry pack, since pay as you go starts at 1 GB on our side too.
Then cut. Five or six packs sell; nine confuse. A ladder of 1, 10, 50, 100, 250 and 1,000 GB covers the first try, the monthly buyer and the bulk buyer, and every rung at least doubles the one below it, which is what makes "the next size up is a better deal" true at each step.
Round to pack prices, downward
Buyers see a pack total, not a per-gigabyte rate, so the last step is rounding the total to a clean figure. Round down, so rounding never pushes you back over the ceiling, then check the floor again. If rounding down crossed the floor, step up one notch and check the ceiling once more. A pack that can't satisfy both has no room at your cost and comes off the ladder.
Take 50 GB. Ten percent under the $1.34 line is $1.206 per GB and $60.30 a pack. Round down to $60 and the rate is $1.20: under $1.34, above $0.84, and a number someone can remember.
Card fees push the small packs. Most processors take a fixed amount per charge on top of a
percentage, and the fixed part is the same on a $4 pack and a $400 pack, so it takes a far
larger share of the small one. The script takes FEE_FIXED and FEE_PCT so the margin
column shows your processor's bite; read your rate card before you print a 1 GB price.
The script
Python, standard library only. The cost per GB is the argument, the lines are the ones above, and every environment variable has a default you can leave alone:
#!/usr/bin/env python3
"""Print a resale ladder that stays under both public lines and above a margin floor.
usage: python3 ladder.py 0.50 # wholesale cost per GB, in CUR
env: CUR=USD|EUR UNDERCUT=0.10 FLOOR=0.40 FEE_FIXED=0 FEE_PCT=0
"""
import os, sys
# Basil's public per-GB lines as (from_gb, rate). Pay as you go from 1 GB,
# subscription bands from 5 GB (plans 10 GB to 2,000 GB).
LINES = {
"USD": { # GET /api/pricing?product=residential¤cy=USD, 2026-09-25
"payg": [(1, 4.20), (2, 3.90), (5, 3.60), (15, 3.00), (30, 1.92), (50, 1.68),
(100, 1.20), (200, 1.14), (500, 1.08), (1000, 0.96)],
"sub": [(5, 2.82), (15, 2.40), (30, 1.54), (50, 1.34), (100, 1.02),
(200, 0.99), (500, 0.96), (1000, 0.90)],
},
"EUR": { # same call with currency=EUR, 2026-10-01
"payg": [(1, 3.50), (2, 3.25), (5, 3.00), (15, 2.50), (30, 1.60), (50, 1.40),
(100, 1.00), (200, 0.95), (500, 0.90), (1000, 0.80)],
"sub": [(5, 2.35), (15, 2.00), (30, 1.28), (50, 1.12), (100, 0.85),
(200, 0.83), (500, 0.80), (1000, 0.75)],
},
}
PACKS = [1, 10, 50, 100, 250, 1000]
cost = float(sys.argv[1])
cur = os.environ.get("CUR", "USD")
undercut = float(os.environ.get("UNDERCUT", 0.10))
floor_rate = cost / (1 - float(os.environ.get("FLOOR", 0.40)))
fee_fixed = float(os.environ.get("FEE_FIXED", 0))
fee_pct = float(os.environ.get("FEE_PCT", 0)) / 100
def rate(line, gb):
"""The band a pack of `gb` falls in, or None below the line's first band."""
hit = [r for start, r in line if gb >= start]
return hit[-1] if hit else None
def step(total):
"""Rounding step for a pack total: 0.50 under 20, 1 under 50, 5 above."""
return 0.5 if total < 20 else 1 if total < 50 else 5
print(f"cost {cost:.2f} {cur}/GB floor {floor_rate:.3f}/GB undercut {undercut:.0%}")
for gb in PACKS:
rates = [r for r in (rate(LINES[cur]["payg"], gb), rate(LINES[cur]["sub"], gb)) if r]
ceiling = min(rates) # the lower public line wins
per_gb = max(ceiling * (1 - undercut), floor_rate) # undercut, but never under the floor
s = step(gb * per_gb)
pack = gb * per_gb // s * s # round down to a clean total
if pack / gb < floor_rate:
pack += s # rounding crossed the floor: step up
if pack / gb > ceiling:
print(f"{gb:>5} GB no room: floor {floor_rate:.2f} is over the ceiling {ceiling:.2f}")
continue
kept = pack - fee_fixed - pack * fee_pct - cost * gb
print(f"{gb:>5} GB {pack:>8.2f} {pack / gb:.3f}/GB ceiling {ceiling:.2f} margin {kept / pack:.0%}")
At the published starting band, python3 ladder.py 0.50 prints this:
cost 0.50 USD/GB floor 0.833/GB undercut 10%
1 GB 3.50 3.500/GB ceiling 4.20 margin 86%
10 GB 25.00 2.500/GB ceiling 2.82 margin 80%
50 GB 60.00 1.200/GB ceiling 1.34 margin 58%
100 GB 90.00 0.900/GB ceiling 1.02 margin 44%
250 GB 220.00 0.880/GB ceiling 0.99 margin 43%
1000 GB 835.00 0.835/GB ceiling 0.90 margin 40%
Read it bottom up. The margin falls from 86% to 40% as the size climbs, every rate sits under its ceiling, and the 1,000 GB rung is pinned to the floor rather than to the undercut. That last line is the script telling you something: at $0.50 the top of your ladder is a margin decision, not a discount decision. Put your real band in and the top rung moves.
Run it with CUR=EUR and a euro cost and it says the same thing more sharply, because the
euro subscription line ends at €0.75 from 1,000 GB. A 40% floor fits under that only when
the cost is under €0.45 per GB, and when it doesn't fit the script drops the rung instead of
printing a price that loses the buyer.
What the ladder doesn't do
It prices packs, not monthly plans. If you sell plans, the same ceilings apply; whether you
offer rollover is your call, and our own rule is in
rollover explained. It doesn't convert currencies: charge in
euros, set CUR=EUR and put your cost in euros. It doesn't know your fees until you tell it.
And it doesn't know your band, because the one wholesale number I publish is the $0.50
start.
Ask for your band on the partners page, run the script with it, and argue with what it prints before you publish it.
Common questions
- How much should I undercut retail when reselling residential proxies?
- Price under the lower of the two public lines at each size, which is the subscription line wherever a plan exists. Ten percent under it is a visible gap; the script in the post takes any undercut you choose.
- What gross margin should a proxy reseller keep?
- At least 40% at the top of the ladder, where the big buyer compares prices, and let the small packs run higher. At $0.50 per GB wholesale, 40% means never printing a price under $0.84 per GB.
- What is Basil's wholesale price for residential gigabytes?
- From $0.50 per GB. The exact band depends on volume and is given on request. A partner's first order is 100 GB, any size after that, and pool gigabytes never expire.
- Why do small packs lose more to card fees?
- Most processors charge a fixed amount per charge on top of a percentage. The fixed part is the same on a $4 pack and a $400 pack, so it takes a far larger share of the small one. Put your processor's fee into the script and the margin column shows it.