Reseller API: act as your customers
For approved resellers: name each of your customers with X-Reseller-Customer-Id and every call runs as them: isolated plans and balances per customer, orders at your negotiated rates, and a customer book with contact identity.
The reselling guide's loop runs everything through YOUR account and tags plans with labels. Approved resellers get a stronger model: your key names one of your customers per request, and the call runs as that customer: their own plans, their own spendable balance, their own order history, fully isolated from every other customer. You price in your business dashboard, we charge you your negotiated rates, and your customers never see us anywhere.
Reseller access is granted, not self-served. Apply from Reseller in your dashboard with the account whose key you already use; we review every application in person and reply on the account's email. Approval provisions your rate card and opens your business dashboard (balance, statement, customers, your prices, storefront, support inbox). Your reseller API key, carrying the act_as_reseller_customer scope, is one you create in that dashboard under Storefront, API access; it is shown once, and you can hold up to three and revoke any of them there. The reselling guide walks the four steps.
Naming a customer
Add one header to any /api/v1 call. The id is yours (your user id, an email hash, anything stable): up to 64 characters of letters, digits, _, -, .. It is scoped to your account, so two businesses using the same id refer to different people and can never see each other's data. The customer is created the first time you name one, so there is no signup call.
curl https://hproxy.com/api/v1/plans \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021"Without the header, the same key acts as your own account (your wallet, your deposits), which is how you top up your reseller balance. With it, reads and writes belong to that customer.
How the money works
Your customers pay you, on your site, with your payment methods. You mirror what they paid you as store credit on that customer (from your business dashboard, or from your own backend with PUT /customer/credit), and their orders spend that credit at your prices while your prepaid reseller balance is charged your negotiated rate in the same transaction. The gap is your margin, and it never appears in anything their side can read. When their credit is short an order fails with 402 customer_credit_insufficient; when your balance is short, 402 reseller_balance_insufficient. Nothing half-charges. Your storefront can also take the payment itself: connect your own gateway (Heleket or NOWPayments for crypto, Stripe or Payoneer Checkout for cards) under Payments in your business dashboard, and POST /deposits for a named customer returns a pay page on your merchant account. What arrives is credited to that customer automatically, underpayments and overpayments included. Without a gateway for the requested method the call answers 403 deposits_not_available; there is never a payment page of ours for your customers to reach.
hproxy.com/api/v1/customerkeycurl https://hproxy.com/api/v1/customer \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021"Read the acting customer
The named customer's profile: your id for them, your display name (label), the email you attached, the credit they can still spend (in cents, at your prices), and when they were created and last seen. Requires the X-Reseller-Customer-Id header.
hproxy.com/api/v1/customer/contactkeycurl -X PUT https://hproxy.com/api/v1/customer/contact \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021" \
-H "Content-Type: application/json" \
-d '{"email": "alex@example.com", "label": "Alex M."}'Attach their identity
Set the customer's email and your display name for them, ideally right after your own signup flow, so your customer book, your business dashboard and our support all see a person instead of an opaque id. Each field: omitted = unchanged, empty string = cleared, value = set. We never send mail to this address; it is identity, not a channel.
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | optional | The customer's email address. Stored lowercased. Empty string clears it. |
label | string | optional | Your display name for them, 1 to 120 characters. Empty string clears it. |
hproxy.com/api/v1/customer/creditkeycurl -X PUT https://hproxy.com/api/v1/customer/credit \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 2500, "direction": "grant", "request_id": "pay_8f3a21", "note": "Stripe pi_3Q…"}'Credit or revoke their balance
Move store credit on the named customer, from your own backend: grant when they paid you, revoke for a refund on your side or a correction. Amounts are whole cents at your retail prices; one movement is at most $5,000. Send your own request_id for every movement (your payment id, your refund id): a repeat with the same id answers 409 already_applied instead of moving the credit twice, so a retry is always safe. A revoke larger than what is left is refused (revoke_exceeds_credit) and names the remaining figure. Requires the X-Reseller-Customer-Id header.
| Parameter | Type | Required | Description |
|---|---|---|---|
amount_cents | integer | required | Positive whole cents at your prices. |
direction | string | required | "grant" or "revoke". |
request_id | string | required | Your id for this movement, one per intent, 1 to 100 characters. |
note | string | optional | Shown on your statement, up to 200 characters. |
hproxy.com/api/v1/depositskeycurl -X POST https://hproxy.com/api/v1/deposits \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021" \
-H "Idempotency-Key: topup_8f3a21" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 2500, "method": "crypto", "return_url": "https://shop.example.com/wallet"}'Let the named customer pay you
With X-Reseller-Customer-Id, this creates an invoice on your own payment gateway (connected under Payments in your business dashboard) and returns its pay page: crypto through Heleket or NOWPayments (method: "crypto"), cards through Stripe Checkout or Payoneer Checkout (method: "card"); one live gateway per rail. The page shows your merchant name, the money goes to your account, and when it arrives we credit the customer's store credit automatically: the exact amount, the whole amount when they overpay, and what actually arrived when a crypto invoice closes short. Amounts are whole cents; sub-floor amounts are raised to the method floor ($3 crypto, $10 card) and one invoice is at most $5,000. Send an Idempotency-Key and a retried request returns the same open invoice. No gateway for that method ⇒ 403 deposits_not_available.
An order can pay for itself. POST /orders for a named customer with method: "crypto" or "card" and short credit still answers 402 customer_credit_insufficient, but with payUrl, depositId, chargeCents (the shortfall raised to the rail's minimum) and shortfallCents added. Send the customer to payUrl: when the money lands, the credit is granted and the order is placed automatically under the same Idempotency-Key, a Telegram customer is told in the store's bot, and GET /deposits/{id} shows for_order: true. Without a gateway for that rail the 402 carries no pay page and the customer needs credit first.
| Parameter | Type | Required | Description |
|---|---|---|---|
amount_cents | integer | required | Whole cents at your prices. |
method | string | optional | "crypto" or "card". Default "card". |
return_url | string | optional | Where the customer lands after paying (https). Default: your website, else your Telegram storefront. |
hproxy.com/api/v1/deposits/{id}keycurl https://hproxy.com/api/v1/deposits/rpay_cmt9x2k1a0001 \
-H "X-API-Key: hpx_your_key_here"Read one of your customers' payments
The state of a deposit your storefront created, for your own backend to show "payment received". status is awaiting_payment, paid, paid_over, underpaid, expired, cancelled, failed, locked (held by the gateway; nothing credited) or needs_review. credited_cents is what landed on the customer's store credit. Account-level: no customer header needed, and only your own deposits resolve.
| Parameter | Type | Description |
|---|
hproxy.com/api/v1/usagekeycurl "https://hproxy.com/api/v1/usage?days=7" \
-H "X-API-Key: hpx_your_key_here" \
-H "X-Reseller-Customer-Id: user-4021"A customer's bandwidth history
With X-Reseller-Customer-Id, the named customer's traffic from the meter: one row per day and one per plan over the last days days (1 to 365, default 30). gbUsed is what was consumed that day; null means no reading exists for that day (a plan's first day, or a gap) and is never zero, and unknownDays counts those. Each day also carries gbTotal (the caps of the plans measured that day) and gbLeft (what they still held at the day's last reading), so how much a customer had and how much is left is a history, not a snapshot. Each plan line carries its cap, the meter at the last reading (gbUsedEnd) and gbLeft. Narrow to one plan with plan_id. What they bought is on GET /orders; this is what they used. Readings land every 30 minutes, one pass after the plan's own figures are synced, so a plan bought in the last hour may have no row yet; for a live figure read the plan itself (GET /plans/{id}).
| Parameter | Type | Required | Description |
|---|---|---|---|
days | integer (query) | optional | Window in days, 1 to 365. Default 30. |
plan_id | string (query) | optional | One plan only. |
hproxy.com/api/v1/store/usagekeycurl "https://hproxy.com/api/v1/store/usage?days=30" \
-H "X-API-Key: hpx_your_key_here"Your whole store's bandwidth
Account-level (no customer header): what all your customers used per day beside what you sold per day, per product, and the ten customers that used the most, over the last days days. gb_used is the meter, gb_sold is GB on paid orders by the day they were paid, gb_total and gb_left are what the measured plans had and still held at the day's last reading; the four are never mixed into one number. unknown_days counts plan-days without a reading. Readings land every 30 minutes, one pass after each plan's own figures are synced. Snake_case like the other account-level doors.
| Parameter | Type | Required | Description |
|---|---|---|---|
days | integer (query) | optional | Window in days, 1 to 365. Default 30. |
hproxy.com/api/v1/customerskeycurl "https://hproxy.com/api/v1/customers?limit=50" \
-H "X-API-Key: hpx_your_key_here"List your customers
Every customer on your account, newest first, with identity and credit, the read your backend reconciles against. This is an account-level call: send it without the X-Reseller-Customer-Id header (naming a customer here is refused with a 400 telling you to drop the header).
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer (query) | optional | Page size, 1 to 200. Default 50. |
offset | integer (query) | optional | Rows to skip. Default 0. |
The whole loop, as one customer
# 0. Your customer signs up on YOUR site -> create + identify them
curl -X PUT https://hproxy.com/api/v1/customer/contact \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021" \
-H "Content-Type: application/json" \
-d '{"email": "alex@example.com", "label": "Alex M."}'
# 1. They paid you -> mirror it as credit, from your backend (or in the
# business dashboard: Customers -> user-4021 -> Add credit)
curl -X PUT https://hproxy.com/api/v1/customer/credit \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 2500, "direction": "grant", "request_id": "pay_8f3a21"}'
# Their balance, any time:
curl https://hproxy.com/api/v1/wallet \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021"
# -> { "balanceCents": 2500, "currency": "USD" } (their credit, your prices)
# 2. They buy on your site -> order AS them (Idempotency-Key is REQUIRED here)
curl -X POST https://hproxy.com/api/v1/orders \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021" \
-H "Idempotency-Key: your-order-83741" \
-H "Content-Type: application/json" \
-d '{"product_id": "residential-lite", "quantity": 5}'
# 3. Deliver: generate lines from THEIR plan (free, repeatable)
curl https://hproxy.com/api/v1/plans \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021"
curl -X POST https://hproxy.com/api/v1/plans/{planId}/generate \
-H "X-API-Key: hpx_your_key_here" -H "X-Reseller-Customer-Id: user-4021" \
-H "Content-Type: application/json" \
-d '{"count": 100, "country": "US", "stickyMinutes": 10}'Dedicated IPs work the same way: list the countries in stock with GET /products/{id}/options (always current, sold-out countries drop out on their own), quote and order with country and period_days in fulfillment_meta while naming the customer, then GET /proxies?order_id=… as that customer once the order completes. Renewals too: the ids must belong to the acting customer, exactly as ownership works everywhere else.
Rules the lane enforces
An Idempotency-Key is required on every reseller order (a plain key merely should send one; a reseller key must, and an order without one is refused before any charge): only your system knows whether a request is a new sale or a retry, and this is what makes retries free. Isolation is structural: a customer id that is not yours simply does not resolve, plan and proxy ownership follow the acting customer, and GET /plans for customer A can never show customer B's plans. Reseller keys also carry a higher rate-limit tier, sized for a whole storefront (thousands of customers behind one key) rather than a single integration, so a busy shop or a bulk operation is never throttled for being busy.
GET /products is your rate card: the products we have priced for you and nothing else, which can include storefront-only products the public catalog does not list. Everything about them (pricing, options, ordering) works exactly like every other product on this page, and every quote on this key is at your prices. The other direction is yours too: a product you hide in your business dashboard (Pricing, then Hide) leaves your catalog and your bot on their next read, and an order for it as one of your customers answers 409 product_unavailable.Lock your key to your servers
Your reseller key is a server-to-server credential, so you can pin it to the IP addresses your own backend calls us from. Set the allowlist in your business dashboard under Storefront → Key access, and the key stops working from anywhere else. A leaked copy is inert. It is off by default, holds a handful of IPv4/IPv6 addresses, and restricts only the API key: the dashboard is a separate, session-authed login, so a wrong entry locks your integration, never you out of fixing it. A call from a disallowed IP is refused with 403 ip_not_allowed.
Need a hand wiring this up? Email support@hproxy.com. A real person reads every message.