Skip to content

Reseller API ​

Programmatic access for approved resellers: browse your product catalog, place balance-paid orders, retrieve proxy credentials, create a separate sub-account for each of your customers, and monitor traffic usage — all over a simple REST API.

Copies the full API docs (Markdown) to your clipboard — paste into ChatGPT / Claude to help you integrate

API at a glance

  • Base URL: https://hellworld.io/openapi/v1 (https://hellworld.io/hellworld/openapi/v1 is an equivalent path to the same API)
  • Auth: Authorization: Bearer <key_id>.<key_secret>
  • Format: JSON over HTTPS
  • Billing: prepaid account balance (USD)
  • Rate limit: per reseller — 300 requests/min (reads), 60/min (writes: orders and sub-account create / top-up / reclaim). Up to 5 active keys per reseller.

Overview ​

The Reseller API is available to approved reseller accounts. Your account manager enables specific products for your account and configures your reseller pricing. Only products enabled for your account appear in the API.

The typical integration loop:

  1. GET /products — see your enabled products and unit prices
  2. POST /orders — place an order, paid from your prepaid balance
  3. GET /orders/{order_ref} — confirm order state
  4. GET /proxies — retrieve proxy credentials and traffic usage
  5. Build proxy strings using the per-product gateway formats below

Reselling to end customers who each need their own login? Use Sub-accounts instead: POST /subusers creates a separate credential with its own traffic quota. You can top it up individually, and reclaim its unused traffic in whole GB for a refund (see DELETE) — reclaiming does not disconnect the sub-account.

Currently available products:

product_codeProductCategoryBillingSub-accounts
MOBILE-ETET Mobilemobileper GByes
RES-GEOFASTGeofastresidentialper GB—
RES-ETHET Hearthresidentialper GByes

A product is usable only once it is enabled and priced for your account — it then appears in your GET /products. More products can be enabled on request.

Authentication ​

Create an API key in your Reseller Portal (Dashboard → Reseller Portal → API Keys). A key has two parts:

  • Key ID — starts with dk_live_, safe to log
  • Key Secret — shown only once at creation; store it securely

Send both on every request, joined by a dot:

Authorization: Bearer dk_live_AbCdEf1234567890.YOUR_KEY_SECRET
bash
curl -s https://hellworld.io/openapi/v1/products \
  -H "Authorization: Bearer dk_live_AbCdEf1234567890.YOUR_KEY_SECRET"

Common pitfalls

  • The header value is Bearer + one space + key_id.key_secret — the first dot separates ID from secret.
  • Write requests also require Content-Type: application/json and an Idempotency-Key header (see Idempotency).
  • Rate limits are per reseller (shared across all your keys): 300 requests/min for reads, 60/min for writes (orders plus sub-account create / top-up / reclaim, one shared budget). On 429 RATE_LIMITED, honor the Retry-After response header. You may hold up to 5 active API keys.
  • Keys can be revoked and re-created in the portal at any time. Revocation is immediate.
  • Python's built-in urllib sends a default User-Agent that our edge network blocks (403). Set your own User-Agent header; the defaults of requests, curl, Node and Go work as-is.

Authentication errors:

HTTPcodeMeaning
401AUTH_MISSING_KEYNo Authorization header
401AUTH_INVALID_KEYMalformed key, unknown key ID, or secret mismatch
401AUTH_KEY_REVOKEDKey was revoked in the portal
401AUTH_KEY_EXPIREDKey past its expiry date
403DEALER_SUSPENDEDReseller account disabled — contact your account manager
429RATE_LIMITEDOver the per-reseller rate limit (300/min read, 60/min write); see Retry-After

API errors share one envelope:

json
{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Account balance is insufficient for this order" } }

A request the server can't parse at all — a write with no body or invalid JSON, a missing Content-Type: application/json, a field of the wrong JSON type (for example a numeric product_code), or a non-numeric pageNum / pageSize — gets a generic error response without this envelope instead (it can be a 4xx or a 500). Nothing is created or charged in that case; fix the request and send it again.

Products ​

GET /products ​

Returns the products enabled for your account, with your unit prices.

bash
curl -s https://hellworld.io/openapi/v1/products \
  -H "Authorization: Bearer $KEY"
json
{
  "data": [
    {
      "product_code": "MOBILE-ET",
      "display_name": "ET Mobile",
      "category": "mobile",
      "billing_unit": "gb",
      "unit_price": 2.50,
      "currency": "USD"
    },
    {
      "product_code": "RES-GEOFAST",
      "display_name": "Geofast",
      "category": "residential",
      "billing_unit": "gb",
      "unit_price": 0.30,
      "currency": "USD"
    }
  ]
}

unit_price is your negotiated reseller price per billing_unit. A product without a unit_price has no price set for your account yet and can't be bought (orders and sub-accounts return 422 NO_DEALER_PRICE) — ask your account manager to configure it.

Balance ​

GET /balance ​

bash
curl -s https://hellworld.io/openapi/v1/balance \
  -H "Authorization: Bearer $KEY"
json
{ "balance": 152.40, "currency": "USD" }

Topping up: log into your account on hellworld.io and use the normal balance recharge (PayPal / crypto / other supported channels), or arrange an offline payment with your account manager — it is credited to the same balance the API spends from.

Orders ​

POST /orders ​

Places an order paid from your prepaid balance. Requires an Idempotency-Key header — 1–64 ASCII characters; allowed characters are A–Z, a–z, 0–9, ., _, : and - (spaces are not allowed; a UUID fits). Anything else is rejected with 422 IDEMPOTENCY_KEY_INVALID.

bash
curl -s -X POST https://hellworld.io/openapi/v1/orders \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-963d-1a4a6e4c1b2f" \
  -d '{ "product_code": "RES-GEOFAST", "quantity": 10 }'
FieldTypeRequiredMeaning
product_codestringyesFrom GET /products
quantitynumberyesAmount in billing_unit (GB), must be > 0

Success — 200:

json
{
  "order_ref": "a1b2c3d4e5f6...",
  "state": "active",
  "total_amount": 3.00,
  "currency": "USD"
}

Traffic is added to your account's proxy credential for that product (see Proxies & Usage). Repeat purchases of the same product top up the same credential.

Accepted — 202 (manual review):

json
{
  "order_ref": "a1b2c3d4e5f6...",
  "state": "manual_review",
  "message": "Order was recorded but pending manual verification; do not retry this request"
}

202 means you were already charged — do NOT retry

A 202 manual_review response means the balance was deducted and the order was recorded, but automatic fulfillment needs manual confirmation. Retrying with a new Idempotency-Key would place (and charge) a second order. Poll GET /orders/{order_ref} until the state becomes completed.

Errors:

HTTPcodeMeaning
400IDEMPOTENCY_KEY_REQUIREDMissing Idempotency-Key header
422IDEMPOTENCY_KEY_INVALIDKey not 1–64 chars of A-Za-z0-9._:-
402INSUFFICIENT_BALANCETop up your balance first
404PRODUCT_NOT_FOUNDNo such product available for your account (unknown code, or not enabled for you)
422NO_DEALER_PRICENo price configured for you — contact your account manager
409 / 422IDEMPOTENCY_KEY_CONFLICTSee Idempotency
422VALIDATION_ERRORMissing/invalid product_code or quantity
422ORDER_REJECTEDOrder could not be created
500ORDER_STATE_UNKNOWNOutcome unverified — do NOT retry with a new key; poll GET /orders or contact support
403SANDBOX_KEY_DISABLEDSandbox keys are not usable yet — create a live key

Idempotency ​

Every POST /orders must carry an Idempotency-Key. Semantics:

SituationResult
Same key, same body, finished beforeThe original response is replayed (no duplicate charge)
Same key, same body, still processing409 IDEMPOTENCY_KEY_CONFLICT — wait, then repeat the same request to fetch the stored result
Same key, different body422 IDEMPOTENCY_KEY_CONFLICT — a key can only ever be used for one request body
Request failed with a validation-type error (VALIDATION_ERROR, PRODUCT_NOT_FOUND, INSUFFICIENT_BALANCE, …)The error is replayed for that key; these are proven side-effect-free — retry with a new key
Request ended in ORDER_STATE_UNKNOWNOutcome could not be verified. Never retry with a new key (possible double charge) — poll GET /orders, or contact support quoting the key

Generate a fresh UUID per order attempt and persist it with your local order record. Keys must match [A-Za-z0-9._:-]{1,64} — max 64 characters, no spaces.

GET /orders ​

Paginated order history (newest first).

bash
curl -s "https://hellworld.io/openapi/v1/orders?pageNum=1&pageSize=20" \
  -H "Authorization: Bearer $KEY"
json
{
  "data": [
    {
      "order_ref": "a1b2c3d4e5f6...",
      "order_no": "CZ20260825...",
      "state": "completed",
      "total_amount": 3.00,
      "currency": "USD",
      "created_at": "2026-08-25 10:12:03",
      "products": [
        { "product_code": "RES-GEOFAST", "display_name": "Geofast", "quantity": 10 }
      ]
    }
  ],
  "pagination": { "page": 1, "page_size": 20, "total": 42 }
}

pageSize is capped at 100.

GET /orders/{order_ref}GET /orders/{ref} ​

Single order lookup — use this to poll the outcome of a 202 manual_review order.

bash
curl -s https://hellworld.io/openapi/v1/orders/a1b2c3d4e5f6 \
  -H "Authorization: Bearer $KEY"

Returns the same object shape as the list endpoint. 404 ORDER_NOT_FOUND if the ref does not exist or does not belong to your account.

Order states:

stateMeaning
pendingCreated, not yet paid
completedPaid; fulfillment done (traffic credited)
manual_reviewPaid; awaiting manual fulfillment confirmation — poll until completed
failedPayment failed; nothing charged
disputedUnder payment dispute
refundedRefunded
unknownAny other internal state

Proxies & Usage ​

GET /proxies ​

Your proxy credentials with traffic usage — one entry per enabled product you have purchased.

bash
curl -s https://hellworld.io/openapi/v1/proxies \
  -H "Authorization: Bearer $KEY"
json
{
  "data": [
    {
      "product_code": "RES-GEOFAST",
      "display_name": "Geofast",
      "billing_unit": "gb",
      "username": "hw_ab12cd34",
      "password": "s3cr3tPass",
      "traffic": { "limit_gb": 50.0, "used_gb": 12.345, "remaining_gb": 37.655 },
      "status": "active",
      "expires_at": null
    }
  ],
  "usage_refresh_seconds": 60
}
FieldMeaning
username / passwordCredentials for the product's proxy gateway (formats below)
traffic.limit_gbTotal GB ever purchased (topped up cumulatively)
traffic.used_gbGB consumed, as last recorded by us — may be out of date (see below)
traffic.remaining_gblimit - used, floored at 0
statusactive, or suspended (e.g. traffic exhausted)
expires_atnull for never-expiring GB balances
usage_refresh_secondsThe shortest interval between usage refresh attempts — not a promise of how recent the values are

Usage may be out of date

used_gb and remaining_gb are the values we last recorded. At the moment, usage may not be refreshed when you call GET /proxies, so these numbers can be well behind actual consumption — by much more than 60 seconds. Treat them as approximate and don't use them to bill your customers or to decide when to cut them off. Polling more than once a minute won't give you fresher data.

Buying more of the same product (POST /orders) increases limit_gb on the same credential — you do not get a new username per order.

Sub-accounts ​

A sub-account is a separate proxy credential — its own username / password and its own traffic quota — that you create through the API for one of your customers. You top it up individually and can reclaim its unused traffic in whole GB for a refund, without touching your other customers. Reclaiming does not disconnect a sub-account: it stays active with the same credentials (see DELETE).

Orders (POST /orders)Sub-accounts (/subusers)
CredentialOne shared credential per product (GET /proxies)A new credential for every sub-account
TrafficAdds GB to your shared credentialEach sub-account has its own quota
Unused trafficStays on your shared credentialReclaim it in whole GB with DELETE /subusers/{subuser_ref} and get a refund; the sub-account stays active
Ending one customer's accessNot possible without affecting the othersNo API call for it — DELETE doesn't disable a sub-account or change its credentials; see Ending a customer's access
Listed in GET /orders, webhooksYesNo — they show only in your balance
ProductsAny product enabled for youMOBILE-ET, RES-ETH

Use orders when you consume the traffic yourself or share one login; use sub-accounts when you resell to end customers who each need their own login and quota.

Endpoints (same base URL, key and rate limits as the rest of this API):

MethodPathDoesCharges
POST/subusersCreate a sub-accountunit_price × quota_gb
GET/subusersList your sub-accounts—
GET/subusers/{subuser_ref}Credentials, quota and usage—
PATCH/subusers/{subuser_ref}Add trafficunit_price × add_gb
DELETE/subusers/{subuser_ref}Reclaim unused traffic in whole GB (the sub-account stays active)Refunds reclaimed_gb × the lowest price you paid

Products & billing ​

Sub-accounts are available for these products (click a product for its connection format):

product_codeProduct
MOBILE-ETET Mobile
RES-ETHET Hearth

You can use one only when it appears in your GET /products with a unit_price; otherwise creation is refused with 404 PRODUCT_NOT_FOUND (not enabled for you) or 422 NO_DEALER_PRICE (no price set) and nothing is charged. GET /products does not mark which products support sub-accounts — use the table above.

How charging works

  • Create and top-up are paid from your prepaid balance at your unit_price per GB: amount = unit_price × GB, rounded to the cent (5 GB at $2.50 → $12.50). The price is fixed at the moment of the request.
  • The GB amount must be at least 0.001 (it is rounded to 6 decimals) and the charge at least $0.01; smaller requests are refused with 422 VALIDATION_ERROR.
  • Reclaiming refunds whole GB. DELETE takes back the whole-GB part of a sub-account's unused paid traffic and refunds it to your balance at the lowest per-GB price you paid for that sub-account; what stays on the sub-account (for example a fraction below 1 GB) is not refunded. See DELETE.
  • Unknown outcomes keep the charge. If a create or top-up ends with 500 SUBUSER_STATE_UNKNOWN or 500 TOPUP_STATE_UNKNOWN, any amount already taken stays deducted while the outcome is reviewed (a few cases settle automatically within minutes; the rest are checked manually by us). Repeat the same request to see the latest state, don't retry with a new key (see Idempotency & retries), and contact support. Likewise, a reclaim that ends with 500 REVOKE_STATE_UNKNOWN refunds nothing while its outcome is reviewed.
  • Sub-account charges and refunds are not orders: they don't appear in GET /orders and no webhook is sent. GET /balance reflects them immediately — keep your own record per subuser_ref.

Effect of each result on your balance:

ResultBalance
200 create / top-upCharged unit_price × GB
200 RECLAIMED (DELETE)Refunded refunded_amount
Create / top-up refused: 400, 402, 404, 503; 422 VALIDATION_ERROR / NO_DEALER_PRICE / LIMIT_EXCEEDED / IDEMPOTENCY_KEY_*; 409 SUBUSER_REF_CONFLICT / SUBUSER_OP_IN_FLIGHT / SUBUSER_NOT_ACTIVE, or IDEMPOTENCY_KEY_CONFLICT for a key used on another endpointNot charged
422 SUBUSER_CREATE_FAILED, 422 TOPUP_FAILEDCharged and refunded — net zero
409 "still processing" (SUBUSER_IN_FLIGHT, TOPUP_IN_FLIGHT, REVOKE_IN_FLIGHT, IDEMPOTENCY_KEY_CONFLICT)The original request is still running — a create or top-up may already be charged, a reclaim may still refund. Repeat the same request with the same key later to get its result; never switch to a new key
500 SUBUSER_STATE_UNKNOWN, 500 TOPUP_STATE_UNKNOWNCharge kept pending review
500 REVOKE_STATE_UNKNOWN (DELETE)No refund while the outcome is reviewed
200 NOTHING_TO_RECLAIM, or a DELETE refused with 400, 404, 422, 501, or 409 REVOKE_NOT_STARTED / SUBUSER_OP_IN_FLIGHTNothing charged, nothing refunded
Same request repeated with the same keyNever charged or refunded twice

Quick start ​

Create → fetch credentials → connect → top up → reclaim. Every write needs its own Idempotency-Key (a fresh UUID); $KEY is your key_id.key_secret.

1. Create a 5 GB ET Mobile sub-account. subuser_ref is your ID for the customer:

bash
curl -s -X POST https://hellworld.io/openapi/v1/subusers \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0b6f3c2e-8d1a-4f7b-9c55-2a7e4d1f6b90" \
  -d '{ "product_code": "MOBILE-ET", "subuser_ref": "cust-1001", "quota_gb": 5 }'
json
{
  "subuser_ref": "cust-1001",
  "status": "active",
  "username": "USERNAME",
  "password": "PASSWORD",
  "traffic": { "limit_gb": 5.000000 }
}

2. Fetch the credentials again whenever you need them:

bash
curl -s https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY"

3. Connect — give your customer a proxy string in the product's format:

bash
curl -x etmobile.hellworld.io:5000 \
  -U "USERNAME-country-us:PASSWORD" \
  https://ipinfo.io

4. Top up 2 GB (wait a few minutes after the previous write — see Timing):

bash
curl -s -X PATCH https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5d2a9e71-3c4b-4e08-a6f1-9b0c7e2d4a13" \
  -d '{ "add_gb": 2 }'
json
{ "subuser_ref": "cust-1001", "status": "active", "traffic": { "limit_gb": 7.000000 } }

5. Reclaim the unused traffic when the customer leaves (again a few minutes after the previous write, while the sub-account is idle):

bash
curl -s -X DELETE https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY" \
  -H "Idempotency-Key: 9a4e1b7c-6f2d-4a83-b5c0-1d8e3f7a2c64"
json
{
  "subuser_ref": "cust-1001",
  "status": "active",
  "code": "RECLAIMED",
  "reclaimed_gb": 6.000000,
  "refunded_amount": 15.00,
  "currency": "USD",
  "remaining_gb": 0.996000,
  "message": "…"
}

Here the customer had used 0.004 GB of the 7 GB, so 6 whole GB came back and $15.00 (6 × $2.50) was added to your balance. The sub-account is still active with the same credentials, and the 0.996 GB left on it keeps working for your customer — DELETE does not disconnect a sub-account (see Ending a customer's access). Rules and other results: DELETE.

POST /subusersCreate (POST) ​

Creates a sub-account and charges unit_price × quota_gb from your balance. Requires Idempotency-Key.

FieldTypeRequiredMeaning
product_codestringyesMOBILE-ET or RES-ETH, as a JSON string (must be enabled and priced for you)
subuser_refstringyesYour own ID for this sub-account: 1–128 characters of A-Za-z0-9._:-, case-sensitive. Unique for your account forever — it can never be reused for another sub-account
quota_gbnumberyesTraffic quota in GB, > 0 (rounded to 6 decimals; at least 0.001 GB and $0.01)

Success — 200:

json
{
  "subuser_ref": "cust-1001",
  "status": "active",
  "username": "USERNAME",
  "password": "PASSWORD",
  "traffic": { "limit_gb": 5.000000 }
}
  • username / password are returned here, when you repeat this exact request with the same key, and by GET /subusers/{subuser_ref} while the sub-account is active. Store them securely.
  • The response has no product_code, created_at or usage — use GET /subusers/{subuser_ref} for those.
  • Creation takes about 10 seconds. Use a client timeout of at least 60 seconds; if it times out, repeat the same request with the same key — never a new key or a new subuser_ref.

Errors:

HTTPcodeMeaning / what to do
400IDEMPOTENCY_KEY_REQUIREDMissing Idempotency-Key header
422IDEMPOTENCY_KEY_INVALIDKey not 1–64 chars of A-Za-z0-9._:-
422VALIDATION_ERRORMissing field, quota_gb not a positive number, bad subuser_ref format, or amount below 0.001 GB / $0.01
404PRODUCT_NOT_FOUNDProduct doesn't support sub-accounts or isn't enabled for your account
422NO_DEALER_PRICENo price configured for you — contact your account manager
402INSUFFICIENT_BALANCETop up, then retry with a new key (the same subuser_ref is still free)
409SUBUSER_REF_CONFLICTThis subuser_ref was already used by an earlier request with a different key — pick a new subuser_ref
409 / 422IDEMPOTENCY_KEY_CONFLICTSee Idempotency & retries
409SUBUSER_IN_FLIGHTYou repeated a request that is still being processed — repeat it later with the same key; if it's unchanged after about 20 minutes, contact support
409SUBUSER_SUSPENDEDYou repeated a create whose sub-account was suspended by the earlier DELETE behaviour (see DELETE)
422SUBUSER_CREATE_FAILEDDefinitely not created; the charge was refunded. Retry with a new subuser_ref and a new key
503SUBUSER_UNAVAILABLECreation temporarily unavailable; nothing charged. Retry later with a new key
500SUBUSER_STATE_UNKNOWNOutcome could not be verified; the charge (if taken) is kept pending review. Do not use a new key or a new subuser_ref; repeat the same request to see the latest state, or contact support with the key and subuser_ref. Also returned when you repeat a create whose sub-account is being reclaimed or awaits support after a reclaim — that sub-account was created and charged once, and repeating doesn't charge again

GET /subusersList (GET) ​

Your sub-accounts, newest first. Query parameters: pageNum (default 1) and pageSize (default 20, max 100).

bash
curl -s "https://hellworld.io/openapi/v1/subusers?pageNum=1&pageSize=20" \
  -H "Authorization: Bearer $KEY"
json
{
  "data": [
    {
      "subuser_ref": "cust-1001",
      "product_code": "MOBILE-ET",
      "status": "active",
      "traffic": { "limit_gb": 7.000000 },
      "created_at": "2026-10-08T02:14:50"
    }
  ],
  "pagination": { "page": 1, "page_size": 20, "total": 1 }
}
  • Lists sub-accounts that are active, pending or unknown (see Status values); a sub-account stays listed after a reclaim. Sub-accounts suspended by the earlier DELETE behaviour, and ones that definitely failed to create, are not listed.
  • List items carry no credentials and no usage — fetch a single sub-account for those.
  • created_at is UTC, written as YYYY-MM-DDTHH:MM:SS without an offset.

GET /subusers/{subuser_ref}Details (GET) ​

One sub-account with its credentials, quota and usage.

bash
curl -s https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY"
json
{
  "subuser_ref": "cust-1001",
  "product_code": "MOBILE-ET",
  "status": "active",
  "username": "USERNAME",
  "password": "PASSWORD",
  "traffic": {
    "limit_gb": 7.000000,
    "used_gb": 0.000000,
    "remaining_gb": 7.000000,
    "usage_source": "cached"
  },
  "usage_refresh_seconds": 60,
  "created_at": "2026-10-08T02:14:50"
}
FieldMeaning
username / passwordProxy credentials — returned only while status is active
traffic.limit_gbTotal GB bought for this sub-account (create + top-ups), minus any GB taken back with DELETE
traffic.used_gbGB consumed, as last recorded by us
traffic.remaining_gblimit_gb − used_gb, floored at 0
traffic.usage_sourcelive = refreshed during this request; cached = last recorded value, possibly out of date
usage_refresh_secondsA refresh is attempted at most once per this many seconds per sub-account
created_atCreation time, UTC, no offset

How fresh the usage numbers are

used_gb / remaining_gb are refreshed from the network during the request, at most once per usage_refresh_seconds per sub-account. usage_source: "live" means this response carries a fresh reading; "cached" means the last recorded value (for example when a refresh was skipped or failed) and may be behind actual consumption. Use only live values to bill or cut off your customers.

Errors: 404 SUBUSER_NOT_FOUND — no such sub-account on your account (also if it failed to create, or was suspended by the earlier DELETE behaviour); 500 SUBUSER_CRED_UNREADABLE — credentials temporarily unreadable, contact support with the subuser_ref.

PATCH /subusers/{subuser_ref}Top up (PATCH) ​

Adds traffic to an active sub-account and charges unit_price × add_gb. The username and password stay the same. Requires Idempotency-Key.

bash
curl -s -X PATCH https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5d2a9e71-3c4b-4e08-a6f1-9b0c7e2d4a13" \
  -d '{ "add_gb": 2 }'
FieldTypeRequiredMeaning
add_gbnumberyesGB to add, > 0 (rounded to 6 decimals; at least 0.001 GB and $0.01)

Success — 200 — limit_gb is the new total quota:

json
{ "subuser_ref": "cust-1001", "status": "active", "traffic": { "limit_gb": 7.000000 } }

Errors:

HTTPcodeMeaning / what to do
400 / 422IDEMPOTENCY_KEY_REQUIRED / IDEMPOTENCY_KEY_INVALIDMissing or malformed key
422VALIDATION_ERRORadd_gb missing or not positive, bad subuser_ref format, or amount below 0.001 GB / $0.01
404SUBUSER_NOT_FOUNDNo active sub-account with this ref (doesn't exist, suspended by the earlier DELETE behaviour, or currently pending / unknown)
404PRODUCT_NOT_FOUNDThe product is no longer enabled for your account
422NO_DEALER_PRICENo price configured for you
402INSUFFICIENT_BALANCETop up, then retry with a new key
409SUBUSER_OP_IN_FLIGHTAnother top-up or reclaim on this sub-account hasn't finished. Nothing charged. Once it has finished, retry with a new key — repeating this key only returns this same 409
409SUBUSER_NOT_ACTIVEThe sub-account stopped being active while the request ran; nothing charged
422LIMIT_EXCEEDEDThe new total would exceed the maximum quota; nothing charged
422TOPUP_FAILEDNot applied; the charge was refunded. Usually the sub-account was changed moments ago — wait 2–3 minutes and retry with a new key. If it keeps happening, contact support
409TOPUP_IN_FLIGHTYou repeated a request that is still being processed (it may already be charged) — repeat it later with the same key, never a new one; if it's unchanged after about 20 minutes, contact support
409 / 422IDEMPOTENCY_KEY_CONFLICTSee Idempotency & retries
500TOPUP_STATE_UNKNOWNOutcome could not be verified; the charge is kept pending review. Until it is resolved, further top-ups and reclaims on this sub-account return 409 SUBUSER_OP_IN_FLIGHT (its credentials keep working). Do not use a new key; contact support with the key and subuser_ref

DELETE /subusers/{subuser_ref}Reclaim (DELETE) ​

DELETE does not disconnect the sub-account

DELETE takes back unused traffic in whole GB and refunds it to your balance. It does not disable the sub-account: the sub-account stays active, its username and password don't change, and the traffic left on it keeps working for your customer. There is currently no API call that disables a sub-account or changes its password — see Ending a customer's access.

This replaces the earlier behaviour, in which DELETE suspended the sub-account and refunded nothing.

Reclaims a sub-account's unused traffic in whole GB and refunds it to your balance. No request body. Requires Idempotency-Key.

bash
curl -s -X DELETE https://hellworld.io/openapi/v1/subusers/cust-1001 \
  -H "Authorization: Bearer $KEY" \
  -H "Idempotency-Key: 9a4e1b7c-6f2d-4a83-b5c0-1d8e3f7a2c64"

Success — 200. The top-level code tells you whether anything was reclaimed. For the sub-account from the quick start (7 GB bought at $2.50 per GB, 0.004 GB used):

json
{
  "subuser_ref": "cust-1001",
  "status": "active",
  "code": "RECLAIMED",
  "reclaimed_gb": 6.000000,
  "refunded_amount": 15.00,
  "currency": "USD",
  "remaining_gb": 0.996000,
  "message": "…"
}

Called again a few minutes later (with a new key), less than 1 GB is left to reclaim:

json
{
  "subuser_ref": "cust-1001",
  "status": "active",
  "code": "NOTHING_TO_RECLAIM",
  "reclaimed_gb": 0.000000,
  "refunded_amount": 0.00,
  "currency": "USD",
  "remaining_gb": 0.996000,
  "message": "…"
}
FieldMeaning
codeRECLAIMED — whole GB were taken back (reclaimed_gb) and refunded_amount was added to your balance. NOTHING_TO_RECLAIM — less than 1 GB of unused paid traffic is left: nothing was taken back or refunded, and nothing changed
statusactive — the sub-account is not disabled and keeps the same credentials (it may have 0 GB left)
reclaimed_gbWhole GB taken back (0 for NOTHING_TO_RECLAIM)
refunded_amount / currencyAmount added to your balance, in USD (0.00 for NOTHING_TO_RECLAIM)
remaining_gbTraffic actually left on the sub-account after this call (including any bonus traffic) — your customer can keep using it. It can differ from traffic.remaining_gb in GET /subusers/{subuser_ref}, which counts only the traffic you paid for
messageHuman-readable summary; it may change — branch on code

How much is reclaimed and refunded

  • Reclaimed: the whole-GB part of the sub-account's unused paid traffic — limit_gb − used_gb, rounded down to a whole number of GB. Usage is measured at the moment of the request, not taken from the cached used_gb of GET. It is never more than the traffic actually left on the sub-account.
  • Stays with the sub-account: everything else — the fraction below 1 GB, and any traffic beyond what you paid for. It is not reclaimed or refunded; settle it with your customer yourself.
  • Refund: reclaimed GB × the lowest per-GB price you paid for this sub-account (at creation or at any successful top-up), rounded to the cent the same way charges are. The refunds for a sub-account never add up to more than you were charged for it.
  • After a reclaim, limit_gb in GET /subusers/{subuser_ref} is lower by reclaimed_gb.
  • If less than 1 GB of unused paid traffic is left — including a sub-account that has used up all of its traffic — the result is NOTHING_TO_RECLAIM: nothing is taken back or refunded and nothing changes, so it's safe to call again.

Example: a sub-account created with 8 GB at $2.50 per GB and later topped up with 2 GB at $2.00 per GB — 10 GB bought, $24.00 charged, refunds at $2.00 per GB:

Used when you reclaimcodereclaimed_gbrefunded_amountLeft on the sub-account
5.2 GBRECLAIMED48.000.8 GB
0 GBRECLAIMED1020.000 GB — it stays active with no traffic
9.6 GBNOTHING_TO_RECLAIM00.000.4 GB
10 GB (all used)NOTHING_TO_RECLAIM00.000 GB

When to reclaim

  • Reclaim while the sub-account is idle. If your customer is still sending traffic through it while the reclaim runs, the result may not be confirmable: you get 500 REVOKE_STATE_UNKNOWN and nothing is refunded while it is reviewed (see If a reclaim can't be confirmed).
  • Leave about 3 minutes after a top-up or a previous reclaim on the same sub-account. A reclaim sent too early is refused safely with 409 REVOKE_NOT_STARTED (nothing changed) — retry later with a new key.
  • A reclaim takes about 10 seconds. Meanwhile the sub-account shows status: "unknown", GET /subusers/{subuser_ref} returns no credentials, and it can't be topped up or reclaimed again. The sub-account is not disabled and its credentials don't change; whether your customer can still use it depends on how much traffic is actually left.

Sub-accounts suspended earlier. Before this change, DELETE suspended the sub-account. Those sub-accounts keep their earlier result: repeating that request returns the same 200 as before — code: "QUOTA_SUSPENDED" (revocation: "drain_confirmed") or code: "QUOTA_SUSPENDED_UNVERIFIED" (revocation: "unverified") — and a new DELETE on such a sub-account returns 200 with code: "QUOTA_SUSPENDED_UNVERIFIED". Both come with status: "suspended" and carry no refund; such a sub-account is no longer listed or returned by GET. No other sub-account gets these two codes.

Errors (the codes of this endpoint keep their earlier REVOKE_… names):

HTTPcodeMeaning / what to do
400 / 422IDEMPOTENCY_KEY_REQUIRED / IDEMPOTENCY_KEY_INVALIDMissing or malformed key
422VALIDATION_ERRORBad subuser_ref format
404SUBUSER_NOT_FOUNDNo such sub-account on your account
409REVOKE_NOT_STARTEDThe reclaim didn't start — usually because the sub-account was changed moments ago (a top-up or a previous reclaim). Nothing changed and nothing was refunded. Wait 2–3 minutes and retry with a new key; if it keeps happening, contact support
409SUBUSER_OP_IN_FLIGHTAnother top-up or reclaim on this sub-account is in progress, or it can't be reclaimed in its current state (pending / unknown). Nothing changed. Once it clears, retry with a new key — repeating this key only returns this same 409; if it persists, contact support
409REVOKE_IN_FLIGHTYou repeated a reclaim that is still running — repeat it later with the same key; if it's unchanged after about 20 minutes, contact support
409REVOKE_IN_PROGRESS_OR_FAILEDThis key has no result yet. Repeat the same request shortly; if it keeps returning this, use a new key or contact support
409 / 422IDEMPOTENCY_KEY_CONFLICTKey already used on another endpoint, or for another sub-account
501REVOKE_NOT_SUPPORTEDReclaim isn't available for this sub-account's product. Nothing changed
500REVOKE_STATE_UNKNOWNThe reclaim's result couldn't be confirmed. No refund while it is reviewed — see If a reclaim can't be confirmed. Do not use a new key; contact support with the key and subuser_ref

If a reclaim can't be confirmedUnconfirmed reclaim ​

500 REVOKE_STATE_UNKNOWN means the reclaim was sent but its result couldn't be confirmed — for example because traffic was flowing through the sub-account at that moment, or the result on the network or our settlement couldn't be confirmed — or it couldn't be completed automatically:

json
{ "error": { "code": "REVOKE_STATE_UNKNOWN", "message": "…" } }

What that means:

  • No refund for now — nothing is added to your balance while we review it.
  • The sub-account is not disabled and its credentials don't change, but some or all of its traffic may already have been taken back — whether your customer can still use it depends on what is actually left. Until the result is confirmed, don't assume nothing was taken back.
  • Until support has resolved it, the sub-account shows status: "unknown" in GET /subusers and GET /subusers/{subuser_ref}. The detail returns no credentials, and the API can't top it up (404 SUBUSER_NOT_FOUND) or reclaim it again (409 SUBUSER_OP_IN_FLIGHT with a new key).
  • Repeating the same request with the same Idempotency-Key is safe but returns the same result — it doesn't resolve on its own.
  • Repeating the sub-account's original create request meanwhile returns 500 SUBUSER_STATE_UNKNOWN. That is not a new charge: the sub-account was created and charged once.

What to do: contact support with the subuser_ref and the Idempotency-Key you used. Don't retry with a new key.

Ending a customer's accessEnding access ​

There is currently no API call that disables a sub-account or changes its password, and DELETE doesn't do either. When a customer leaves:

  1. Stop topping the sub-account up.
  2. Once it is idle, call DELETE to reclaim its unused whole GB for a refund.
  3. What stays on the sub-account — the fraction below 1 GB, and any traffic beyond what you paid for — keeps working with the same credentials until it is used up. Settle that part with your customer yourself.

A subuser_ref can't be reused for another sub-account; give a new customer a new ref.

Idempotency & retriesIdempotent retries ​

POST /subusers, PATCH and DELETE all require an Idempotency-Key — 1–64 characters of A-Za-z0-9._:-, same as orders. Use a fresh UUID for every new operation and store it with your record, so you can repeat the request after a timeout.

SituationResult
Same key, same request, already finishedReturns that operation's current result; never charged or refunded twice. While the sub-account is active — also after a reclaim — a repeated create returns the current credentials and the current limit_gb (after later top-ups and reclaims); while a reclaim is running or awaits support it returns 500 SUBUSER_STATE_UNKNOWN, and for a sub-account suspended by the earlier DELETE behaviour 409 SUBUSER_SUSPENDED — none of these is a new charge. A repeated reclaim returns the same code and amounts as the first time
Same key, same request, still running: 409 SUBUSER_IN_FLIGHT, TOPUP_IN_FLIGHT, REVOKE_IN_FLIGHT, REVOKE_IN_PROGRESS_OR_FAILED, or IDEMPOTENCY_KEY_CONFLICT ("already being processed")Repeat the same request with the same key later. Don't switch to a new key — a create or top-up may already be charged and would run a second time, and a reclaim may still complete. These normally clear within seconds; if the same 409 keeps coming back for more than about 20 minutes, contact support with the key and subuser_ref
Same key, different body or different subuser_ref422 IDEMPOTENCY_KEY_CONFLICT
Same key already used on another endpoint (including POST /orders)409 IDEMPOTENCY_KEY_CONFLICT — keys are shared by all your write endpoints
Refused with 400, 402, 404, 422, 503, or a 409 other than the "still running" codes above (for example SUBUSER_REF_CONFLICT, SUBUSER_OP_IN_FLIGHT, REVOKE_NOT_STARTED)Fix the cause and retry with a new key (after SUBUSER_CREATE_FAILED or SUBUSER_REF_CONFLICT, also a new subuser_ref); the old key may keep returning the same error
500 SUBUSER_STATE_UNKNOWN / TOPUP_STATE_UNKNOWN / REVOKE_STATE_UNKNOWNNever retry with a new key or a new subuser_ref — that could create or charge twice. Repeating the same request is safe and returns the latest state; contact support with the key and subuser_ref
  • A repeat must be exactly the same request: same path, same JSON fields in the same order, same number formatting (1 and 1.0 differ). Whitespace doesn't matter.
  • Treat keys as case-insensitive: never use two keys that differ only in letter case.
  • Keys don't expire.
  • Handle results by code; message texts are for humans and may change.

Status values ​

statusMeaningCredentials in detailTop up / reclaim
activeReady to use — also after a reclaimyesyes
pendingBeing created (normally about 10 seconds)nono
unknownA reclaim is running, or an outcome is being verified / awaits supportnono
suspendedOnly sub-accounts suspended by the earlier DELETE behaviour: appears only in the DELETE response, next to code QUOTA_SUSPENDED / QUOTA_SUSPENDED_UNVERIFIED; such a sub-account is not returned otherwise——

Timing & good practiceTiming & tips ​

  • Writes take about 10 seconds. Use a client timeout of at least 60 seconds; after a timeout, repeat the same request with the same key.
  • Leave about 3 minutes between two writes on the same sub-account (create → top-up → reclaim). Readings take a little while to settle after a change; a write sent too early is refused safely — 422 TOPUP_FAILED (refunded) or 409 REVOKE_NOT_STARTED (nothing changed) — and you retry later with a new key.
  • DELETE never cuts a customer off: the sub-account stays active with the same credentials. See Ending a customer's access.
  • Reclaim only while the sub-account is idle; with traffic flowing, the result may not be confirmable (500 REVOKE_STATE_UNKNOWN, no refund while it is reviewed).
  • Writes share the 60 requests/min reseller write limit with POST /orders; reads have 300/min.
  • Sub-account credentials work with your custom gateway domain exactly like GET /proxies credentials.

Proxy Formats ​

Build proxy strings with the username / password from GET /proxies, or from a sub-account (GET /subusers/{subuser_ref}) — the syntax is the same. Country targeting and sticky sessions are encoded in the username.

ET Mobile (MOBILE-ET)ET Mobile ​

Gatewayetmobile.hellworld.io
Port5000
ProtocolsHTTP / HTTPS

Rotating (new IP per request):

etmobile.hellworld.io:5000:USERNAME-country-us:PASSWORD

Sticky session (same IP for the TTL):

etmobile.hellworld.io:5000:USERNAME-country-us-sid-a1b2c3d4-ttl-10m:PASSWORD
  • -country-<cc> — optional 2-letter country code, lowercase (omit for global random)
  • -sid-<id> — any 8-char alphanumeric session ID; same sid = same IP
  • -ttl-<N>m — session lifetime in minutes
bash
curl -x etmobile.hellworld.io:5000 \
  -U "USERNAME-country-us-sid-a1b2c3d4-ttl-10m:PASSWORD" \
  https://ipinfo.io

Geofast (RES-GEOFAST)Geofast ​

Gatewaygeofast.hellworld.io
Port (HTTP/HTTPS)6969
Port (SOCKS5)9696

Rotating:

geofast.hellworld.io:6969:USERNAME-country-US:PASSWORD

Sticky session (~10 min, same session = same IP):

geofast.hellworld.io:6969:USERNAME-country-US-session-a1b2c3d4e5:PASSWORD
  • -country-<CC> — optional 2-letter country code, uppercase (omit for global random)
  • -session-<id> — any 10-char alphanumeric session ID
bash
curl -x geofast.hellworld.io:6969 \
  -U "USERNAME-country-US-session-a1b2c3d4e5:PASSWORD" \
  https://ipinfo.io

For SOCKS5 use port 9696 with the same username syntax.

ET Hearth (RES-ETH)ET Hearth ​

Gatewayethearth.hellworld.io
Port5000
ProtocolsHTTP / HTTPS

Rotating (new IP per request):

ethearth.hellworld.io:5000:USERNAME-country-us:PASSWORD

Sticky session (same IP for the TTL):

ethearth.hellworld.io:5000:USERNAME-country-us-sid-a1b2c3d4-ttl-10m:PASSWORD
  • -country-<cc> — optional 2-letter country code, lowercase (omit for global random)
  • -sid-<id> — any 8-char alphanumeric session ID; same sid = same IP
  • -ttl-<N>m — session lifetime in whole minutes, 1–240
  • State, city and ISP targeting are also available (they go between the country and the session parts); ask your account manager for the codes.
bash
curl -x ethearth.hellworld.io:5000 \
  -U "USERNAME-country-us-sid-a1b2c3d4-ttl-10m:PASSWORD" \
  https://ipinfo.io

Custom Gateway Domain (White-label)Custom Gateway Domain ​

By default your customers connect to the shared gateway hostnames above (etmobile.hellworld.io, geofast.hellworld.io, ethearth.hellworld.io). If you want them to connect through your own branded domain, add a CNAME record pointing at our gateway — no code changes, and no impact on speed.

Setup ​

Add one CNAME per gateway you use, pointing at our gateway hostname:

Your recordTypeTarget
mproxy.yourbrand.comCNAMEetmobile.hellworld.io
proxy.yourbrand.comCNAMEgeofast.hellworld.io
rproxy.yourbrand.comCNAMEethearth.hellworld.io

Customers then connect exactly as before, swapping only the hostname — ports and username syntax are unchanged:

proxy.yourbrand.com:6969:USERNAME-country-US-session-a1b2c3d4e5:PASSWORD

Rules ​

  • Always CNAME to our *.hellworld.io gateway hostname (e.g. geofast.hellworld.io) — never to a raw IP address. We may update the gateway's underlying IPs at any time; because your record points at our hostname, those changes are picked up automatically with no action on your side. A record pinned to a fixed IP will break when the IP changes.
  • DNS-only — do NOT put a CDN/proxy layer in front (e.g. Cloudflare's orange-cloud). Proxy ports are raw TCP; routing them through a CDN breaks the connection. Keep the record grey-cloud / DNS-only.
  • Ports stay the same (ET Mobile 5000, ET Hearth 5000, Geofast HTTP 6969 / SOCKS5 9696).
  • Credentials are still issued by this API — a custom domain only rebrands the hostname; the username / password always come from GET /proxies or from a sub-account.

Does it affect speed? ​

No. A custom domain is a pure DNS alias — proxy traffic still goes directly to the gateway IP and never passes through our servers or the extra hostname. The added CNAME hop only affects the first DNS lookup (a few milliseconds, then cached); actual proxy latency and throughput are identical to using the shared hostname.

Webhooks ​

Get notified when an API order is created, instead of polling. Configure the target URL in the Reseller Portal (Webhook section) — you receive a signing secret there. Sub-account operations don't send webhooks.

Event: order.created — sent after an API order is recorded (active or manual_review):

json
{
  "event_type": "order.created",
  "event_id": "…",
  "dealer_uuid": "…",
  "created_at": "2026-08-25T10:12:03Z",
  "data": {
    "order_ref": "a1b2c3d4e5f6...",
    "state": "active",
    "total_amount": 3.00,
    "currency": "USD"
  }
}

Signature — every delivery carries:

X-Dealer-Signature: sha256=<hex>

where <hex> is HMAC-SHA256(webhook_secret, raw_request_body). Verify before trusting:

js
const crypto = require('crypto');
function verify(rawBody, header, secret) {
    const expected = 'sha256=' + crypto.createHmac('sha256', secret)
        .update(rawBody).digest('hex');
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Delivery & retries: your endpoint must return 2xx within a few seconds. Failed deliveries are retried with exponential backoff (30s, 60s, 120s, … capped at 1h) up to 12 attempts, then dropped. Use the portal's Test webhook button to verify your endpoint (webhook.test event).

TIP

Webhooks are best-effort push. For a guaranteed view of order outcomes (especially manual_review transitions), poll GET /orders/{order_ref}.

Error Reference ​

HTTPcodeWhereMeaning
400IDEMPOTENCY_KEY_REQUIREDall writesMissing Idempotency-Key header
422IDEMPOTENCY_KEY_INVALIDall writesKey not 1–64 chars of A-Za-z0-9._:-
401AUTH_MISSING_KEYallNo Authorization header
401AUTH_INVALID_KEYallMalformed/unknown key or bad secret
401AUTH_KEY_REVOKEDallKey revoked
401AUTH_KEY_EXPIREDallKey expired
402INSUFFICIENT_BALANCEPOST /orders, POST/PATCH /subusersPrepaid balance too low
403DEALER_SUSPENDEDallReseller account disabled
404PRODUCT_NOT_FOUNDPOST /orders, POST/PATCH /subusersNo such product available for your account
422NO_DEALER_PRICEPOST /orders, POST/PATCH /subusersNo price set for your account — contact your account manager
404ORDER_NOT_FOUNDGET /orders/{ref}No such order on your account
409IDEMPOTENCY_KEY_CONFLICTall writesSame key still processing — repeat later; or key already used on another endpoint
422IDEMPOTENCY_KEY_CONFLICTall writesSame key, different body (or different subuser_ref)
422VALIDATION_ERRORall writesBad or missing field, or amount too small
422ORDER_REJECTEDPOST /ordersOrder refused
429RATE_LIMITEDallOver per-reseller limit (300/min read, 60/min write); see Retry-After
500INTERNAL_ERRORanyUnexpected server error
500ORDER_STATE_UNKNOWNPOST /ordersOutcome unverified — never retry with a new key; poll GET /orders
403SANDBOX_KEY_DISABLEDallSandbox keys are disabled until the sandbox launches
404SUBUSER_NOT_FOUND/subusers/{ref}No such sub-account on your account (for PATCH: no active one)
409SUBUSER_REF_CONFLICTPOST /subuserssubuser_ref already used — pick a new one
409SUBUSER_IN_FLIGHTPOST /subusersStill being created — repeat the same request (same key) later
409SUBUSER_SUSPENDEDPOST /subusersRepeated create of a sub-account suspended by the earlier DELETE behaviour
422SUBUSER_CREATE_FAILEDPOST /subusersNot created, charge refunded — retry with a new subuser_ref and key
503SUBUSER_UNAVAILABLEPOST /subusersCreation temporarily unavailable, not charged — retry later with a new key
500SUBUSER_STATE_UNKNOWNPOST /subusersOutcome unverified, charge kept pending review (or, on a repeated create, the sub-account is being reclaimed or awaits support after a reclaim) — never retry with a new key or subuser_ref
500SUBUSER_CRED_UNREADABLEGET /subusers/{ref}Credentials temporarily unreadable — contact support
409SUBUSER_OP_IN_FLIGHTPATCH, DELETE /subusers/{ref}Another operation is running, or the sub-account can't be reclaimed now — retry later with a new key
409SUBUSER_NOT_ACTIVEPATCH /subusers/{ref}Sub-account is no longer active; not charged
422LIMIT_EXCEEDEDPATCH /subusers/{ref}New total would exceed the maximum quota; not charged
422TOPUP_FAILEDPATCH /subusers/{ref}Not applied, charge refunded — retry in 2–3 min with a new key
409TOPUP_IN_FLIGHTPATCH /subusers/{ref}Still processing, may already be charged — repeat the same request (same key) later
500TOPUP_STATE_UNKNOWNPATCH /subusers/{ref}Outcome unverified, charge kept pending review — never retry with a new key
409REVOKE_NOT_STARTEDDELETE /subusers/{ref}Reclaim didn't start, nothing changed — retry in 2–3 min with a new key
409REVOKE_IN_FLIGHTDELETE /subusers/{ref}Still processing — repeat the same request (same key) later
409REVOKE_IN_PROGRESS_OR_FAILEDDELETE /subusers/{ref}No result yet for this key — repeat shortly; then a new key or support
501REVOKE_NOT_SUPPORTEDDELETE /subusers/{ref}Reclaim isn't available for this product; nothing changed
500REVOKE_STATE_UNKNOWNDELETE /subusers/{ref}Result unverified, no refund while it is reviewed — never retry with a new key; contact support (see If a reclaim can't be confirmed)

FAQ ​


How do I become a reseller / get products enabled?

Reseller accounts are set up by our team: your account is registered as a reseller, products are whitelisted, and your pricing is configured. Contact support or your account manager.


How do I pay?

The API spends your prepaid account balance. Top up online (log into hellworld.io → balance recharge: PayPal, crypto, and other supported channels) or arrange an offline payment with your account manager.


I placed an order but GET /proxies shows nothing.

GET /proxies only lists products that are (a) enabled for your account and (b) already purchased at least once. Right after your first order it can take a moment for the credential to be provisioned — check GET /orders/{order_ref} is completed, then retry.


Does every order create a new proxy account?

No. Purchases of the same product accumulate on one credential per product — limit_gb grows, the username stays the same. If you need a separate login per customer, use Sub-accounts.


How fresh is used_gb?

Not guaranteed. At the moment, usage may not be refreshed when you call GET /proxies, so used_gb can be well behind actual consumption. usage_refresh_seconds (60) is only the shortest interval between refresh attempts, not a promise of freshness. Treat the value as approximate, don't bill or cut off customers based on it, and don't poll more than once a minute — that won't give you fresher data. For sub-accounts, see the next question.


Is sub-account usage live?

GET /subusers/{subuser_ref} refreshes usage during the request, at most once per usage_refresh_seconds per sub-account. Check usage_source: live means this response carries a fresh reading; cached is the last recorded value (the refresh was skipped or failed) and may be behind actual consumption. The refresh interval is a throttle, not a freshness guarantee. Bill or cut off customers only on live values.


Sub-account or order — which should I use?

Orders top up one shared credential per product — fine when you use the traffic yourself. Sub-accounts give each customer their own login and quota, which you can top up separately and reclaim separately (unused whole GB, refunded to your balance). See Sub-accounts.


Can I reuse a subuser_ref?

Not once a sub-account has been created with it. After a create that returned 200, 409 SUBUSER_IN_FLIGHT, 422 SUBUSER_CREATE_FAILED or 500 SUBUSER_STATE_UNKNOWN, treat the ref as taken forever — also after a reclaim. A create that was refused before anything was created (400, 402, 404, 503, or 422 VALIDATION_ERROR / NO_DEALER_PRICE / IDEMPOTENCY_KEY_*) leaves the ref free. Use a new ref for every new sub-account (for example your customer ID plus a counter).


Is unused sub-account traffic refunded?

In whole GB, yes. DELETE /subusers/{subuser_ref} reclaims the whole-GB part of a sub-account's unused paid traffic and refunds it at the lowest per-GB price you paid for that sub-account. The fraction below 1 GB, and any traffic beyond what you paid for, stays on the sub-account and isn't refunded. Details: DELETE.


Where do I see what sub-accounts cost me?

In your balance (GET /balance). Sub-account charges and refunds are not orders, so they don't appear in GET /orders and don't send webhooks — keep your own log per subuser_ref and Idempotency-Key.


Does DELETE cut my customer off?

No. DELETE reclaims unused whole GB for a refund; the sub-account stays active, its credentials don't change, and the traffic left on it keeps working. There is currently no API call that disables a sub-account or changes its password — see Ending a customer's access.


My reclaim returned 500 REVOKE_STATE_UNKNOWN. What now?

The reclaim's result couldn't be confirmed — for example because traffic was flowing through the sub-account at that moment, or the result on the network or our settlement couldn't be confirmed. Nothing is refunded while we review it, and until then the API can't top up or reclaim that sub-account. It is not disabled and its credentials don't change, but its remaining traffic may already have been reduced or taken back. Contact support with the subuser_ref and the Idempotency-Key. Don't retry with a new key. Details: If a reclaim can't be confirmed.


My top-up returned 422 TOPUP_FAILED (or my reclaim 409 REVOKE_NOT_STARTED).

Nothing happened: no traffic was added or taken back, and nothing was charged or refunded (a top-up charge is refunded right away). This is usually because the sub-account was changed moments before — wait 2–3 minutes and retry with a new Idempotency-Key. If it keeps happening, contact support.


I got 202 manual_review — was I charged?

Yes. The order is recorded and your balance was deducted; fulfillment just needs a manual confirmation on our side. Do not retry with a new Idempotency-Key (that would be a second, separate order). Poll GET /orders/{order_ref}.


Is there a sandbox?

Not yet — sandbox keys are currently rejected on all API calls (403 SANDBOX_KEY_DISABLED). A mock sandbox is planned.


Can I get more products over the API?

Yes — any catalogued product can be enabled for your account. Ask your account manager.

All-in-one proxy platform — Residential, Mobile, ISP & Unlimited proxies.