Proxy./ docs

Build a reseller business on HProxy

The reseller loop over the HProxy API: fund a wallet, sell residential GB or dedicated IPs, deliver programmatically, get pushed on fulfillment and renew.

Everything a proxy storefront needs, over one API: prepaid wallet, server-authoritative quotes, idempotent orders, programmatic delivery for both residential lines and dedicated IPs, webhooks on fulfillment, and renewals. Your customers never see HProxy: every response is white-label by construction.

  1. 1
    Fund the wallet
    POST /deposits returns a hosted payUrl (card or crypto). Everything below prepays from this balance and fails with an honest 402 when it's short. No surprise card charges, ever.
  2. 2
    Quote before you sell
    GET /products/{id}/price returns the exact amount the order will charge. For dedicated IPs pass country and period_days too. Put your margin on top and show YOUR price.
  3. 3
    Buy on demand
    POST /orders with an Idempotency-Key. Wallet-paid orders return in seconds; a retry with the same key can never double-charge. For residential the body is product_id plus quantity in GB and nothing else: the country is chosen in the next step.
  4. 4
    Deliver
    Residential: POST /plans/{id}/generate per customer request. Dedicated: GET /proxies?order_id=… once the order completes.
  5. 5
    Attribute
    PATCH /plans/{id} with a label. Your reference rides on every read and every webhook for that plan after that.
  6. 6
    Get pushed, don't poll
    Register a webhook: order.fulfilled fulfills the sale, plan.low_traffic prompts the top-up.
  7. 7
    Renew
    POST /orders with fulfillment_meta: {"kind": "extension", "ids": […]} renews exactly the proxies your customer keeps.

Selling residential GB: how plans work

One account holds one active plan per residential product, and every purchase tops it up. Buy 5 GB of residential-lite, then 3 GB more, and you have one plan with 8 GB, one credential pair and one balance. Generation is free and repeatable: every line you generate is that same credential with the country and session written into the username, and the plan's GB is drawn down only by the traffic that actually flows. There is no per-line metering, so lines you hand to different people share one balance.

That is the right shape for your own usage, trials and burst capacity, and the wrong shape for selling to more than one customer: whoever generates lines first can spend the other's traffic, and nothing in this lane can stop them. Isolation per customer is the Reseller API, described below: one header names your customer, and the call runs as an account of their own, with its own plan, its own credentials, its own GB cap and its own balance. That is the sub-user model, and it is the lane a storefront should be on before its second customer.

Residential loop, single account
# The single-account loop: your own usage, or one trial pool.
# 1. Buy 10 GB. A later purchase of the same product tops up this plan.
curl -X POST https://hproxy.com/api/v1/orders \
  -H "X-API-Key: hpx_your_key_here" -H "Idempotency-Key: pool-resi-10gb" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "residential-lite", "quantity": 10}'

# 2. Your plan (one per residential product), with its remaining GB
curl https://hproxy.com/api/v1/plans -H "X-API-Key: hpx_your_key_here"

# 3. Tag it with your own reference
curl -X PATCH https://hproxy.com/api/v1/plans/{planId} \
  -H "X-API-Key: hpx_your_key_here" -H "Content-Type: application/json" \
  -d '{"label": "trial-pool"}'

# 4. Generate lines (free, repeatable; GB is spent by traffic only)
curl -X POST https://hproxy.com/api/v1/plans/{planId}/generate \
  -H "X-API-Key: hpx_your_key_here" -H "Content-Type: application/json" \
  -d '{"count": 100, "country": "US", "stickyMinutes": 10}'

# 5. Read the balance any time (synced about every 30 minutes)
curl https://hproxy.com/api/v1/plans/{planId} -H "X-API-Key: hpx_your_key_here"
Updated
Updated 2026-09-03. An earlier version of this section described a per-purchase plan model that no longer applies: a purchase of a residential product tops up the plan you hold for it. If you built on the older wording, read plan ids from GET /plans after each order instead of expecting a new one, and use the Reseller API below for isolation per customer.

Sub-users: one account per customer, over one header

On the Reseller API your key names a customer with X-Reseller-Customer-Id, and every call runs as that customer: POST /orders provisions their own plan and credentials, GET /plans lists only theirs, GET /wallet is the credit you issued them, and GET /customers is your whole book. Customer A can never generate from customer B's plan, because they are different accounts. Nothing else about the API changes. The lane is granted rather than self-served, and getting on it is four steps:

  1. 1
    Apply from your dashboard
    Sign in and open Reseller: your business name, a few lines about what you sell, and the Partner Agreement. The application is tied to the account whose key you already use, so there is nothing to re-create.
  2. 2
    We review it, in person
    Every partner is onboarded by a person, the founder included. We reply on the email of your account and ask for a Telegram or WhatsApp contact, so you have a direct line for the whole time you sell on the platform.
  3. 3
    Approval provisions the lane
    Your account gets a rate card and a business dashboard (balance, customers, your prices, statement, support inbox). In the dashboard, under Storefront, API access, you create your reseller API key yourself: it carries the act_as_reseller_customer scope, it is shown once, and it is the key that names customers. The key you have today keeps working for your own account.
  4. 4
    Put customers behind the header
    Add X-Reseller-Customer-Id: <your id for them> to any call. The first call creates the customer; PUT /customer/contact attaches their email and a display name; an order as them provisions their own plan. The full loop is on the Reseller API page.

Selling dedicated IPs (IPv4 / IPv6 / ISP / Mobile)

Dedicated loop
# 0. Show your customer the countries in stock right now (name + alpha3),
#    plus the rental periods. Always current: sold-out countries drop out.
curl https://hproxy.com/api/v1/products/ipv4/options -H "X-API-Key: hpx_your_key_here"

# 1. Quote the exact charge for the targeting your customer picked
curl "https://hproxy.com/api/v1/products/ipv4/price?quantity=5&country=DEU&period_days=30" \
  -H "X-API-Key: hpx_your_key_here"

# 2. Buy with the same targeting
curl -X POST https://hproxy.com/api/v1/orders \
  -H "X-API-Key: hpx_your_key_here" -H "Idempotency-Key: cust-1042-ipv4-de-5" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "ipv4", "quantity": 5,
       "fulfillment_meta": {"country": "DEU", "period_days": 30}}'

# 3. On the order.fulfilled webhook (or once GET /orders/{id} says completed):
curl "https://hproxy.com/api/v1/proxies?order_id={orderId}" -H "X-API-Key: hpx_your_key_here"
# -> ip, ports, username, password per proxy. Hand them to your customer.

# 4. Renewal, 30 more days for the proxies the customer kept
curl -X POST https://hproxy.com/api/v1/orders \
  -H "X-API-Key: hpx_your_key_here" -H "Idempotency-Key: cust-1042-renew-jul" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "ipv4", "quantity": 2,
       "fulfillment_meta": {"kind": "extension", "ids": ["9214321", "9214322"], "period_days": 30}}'

Renewals are ownership-checked server-side: the ids (from GET /proxies) must belong to the calling account, and the renewal is priced for exactly those proxies. quantity should match the number of ids.

Selling scrapers

A scraper call is charged to your own balance at our normal per-call price, the same as for every customer, whether you call it for yourself or for a customer of yours. Put your own price on top in your billing. The Scraper API pages list every endpoint and its price.

Scrapers change often
A scraper reads a website we do not control. When that website changes its pages, its limits or how it blocks automated traffic, a scraper can fail, return fewer fields, or return fields in a different shape until we update it, and we update scrapers often. Scrapers are not a stable product that never breaks. Handle errors and retry, read the fields inside data defensively, subscribe to service notices, and do not promise your customers that a scraper will never change or never fail. The envelope around data keeps its shape.

What stays stable when we change things underneath

The networks behind a product change, sometimes at short notice, and a storefront should never notice. Build on the things we keep stable and treat everything else as a value to read, not to remember:

  1. 1
    Product ids
    residential-lite, residential-premium, ipv4 and the rest are ours and stay put when the pool behind them is swapped. Read GET /products for available and the targeting contract instead of hardcoding either.
  2. 2
    Plan ids and balances
    A plan id never changes meaning: the plan keeps serving its remaining gigabytes from the pool it was bought on. When we move a product to a new pool, the next purchase of that product opens a fresh plan beside the old one, so for a while GET /plans can list two plans for one product. List plans and read their balances rather than assuming one per product, and read plan ids from the API after an order completes rather than predicting them.
  3. 3
    Lines, generated on demand
    Generate through POST /plans/{id}/generate when a customer needs lines, and hand those out. The credentials inside a line can rotate when a pool moves, so do not store lines for longer than a session or bake them into a customer's config.
  4. 4
    Order and proxy ids
    Renewals and lookups run on our ids (orderId, the id in GET /proxies), never on anything that names a network.
  5. 5
    Notices
    A change that needs something from you arrives as an ACTION_REQUIRED service notice: in the feed, as the announcement.published webhook, and by email to the account. Subscribe once and you will not learn about a change from a failing request.

Our side of it: fields and codes are only ever added, never renamed or removed, and an existing code keeps its meaning. If a call ever has to change how it behaves, the change is announced as an ACTION_REQUIRED notice with a date before it happens, and the old behaviour keeps working until that date. Nothing in a response names a network or a provider, so a pool change is not something your code can see.

Safety rails for production

Send an Idempotency-Key on every write, so retries converge instead of double-charging. Put a daily spend cap on the key in your dashboard, so a leak can't drain the wallet. Verify webhook signatures before trusting a delivery. Branch on the machine code in error bodies (402 = top up, 429 = back off per Retry-After). And generate your client from the OpenAPI spec instead of hand-writing one.

White-label by construction
Responses never name upstream networks or infrastructure partners, so your storefront stays fully white-label.
The sub-user lane
Selling to more than one customer? Apply for the Reseller API from your dashboard: one account per customer, isolated plans and balances, your negotiated rates, and a customer book with names and emails.

Need a hand wiring this up? Email support@hproxy.com. A real person reads every message.

Proxy.· developer documentation