SDKs
Node.js / TypeScript SDK
The official Node.js / TypeScript library for BuyProxy: generate residential, mobile, ISP and datacenter proxies, check bandwidth, buy more by card or crypto, and run a reseller business. Works on Node.js 18+, Bun, Deno, Cloudflare Workers and browsers (server-side keys only โ never ship an API key to a browser). Ships ESM and CommonJS builds and complete .d.ts types.
Zero dependencies โ uses the platform's
fetchComplete TypeScript types for every request and response
Automatic retries with back-off for rate limits (
429) and transient errorsTyped errors:
AuthenticationError,InsufficientBandwidthError,RateLimitError, โฆHelpers for Playwright, Puppeteer, Axios and environment variables
Source, issues and releases: github.com/DishantSinghDev2/buyproxy-node
Installation
npm install buyproxy
# or: pnpm add buyproxy ยท yarn add buyproxy ยท bun add buyproxyNode.js 18+, Bun, Deno, Cloudflare Workers and any runtime with a global fetch. Ships ESM and CommonJS builds with full .d.ts types.
Authentication
Create an API key under Dashboard โ API keys โ personal keys start bp_key_, reseller keys bp_live_. The SDK reads BUYPROXY_API_KEY from the environment automatically; you can also pass the key explicitly. A missing key fails immediately with an authentication error, without a network call.
// 1. Environment variable (recommended) โ nothing to pass
const bp = new BuyProxy();
// 2. Explicit key, e.g. from a secrets manager
const bp2 = new BuyProxy({ apiKey: await getSecret("buyproxy") });
// 3. Find out which kind of key you're holding
console.log(bp.keyKind); // "personal" | "reseller" | undefinedQuick start
import { BuyProxy } from "buyproxy";
const bp = new BuyProxy({ apiKey: process.env.BUYPROXY_API_KEY }); // or just set BUYPROXY_API_KEY
// 1. See what you have
const balances = await bp.balances.list();
const [plan] = await bp.plans.list();
// 2. Generate 5 US proxies in Austin, rotating on every request
const { proxies } = await bp.plans.generate(plan.id, { country: "US", city: "Austin", count: 5 });
console.log(proxies[0].url); // http://user-country-us-city-austin:pass@gw.buyproxy.org:6969Add stickyMinutes: 10 to keep the same IP for ten minutes, or protocol: "socks5" for SOCKS5.
Generating proxies
Generation is free and instant โ bandwidth is only consumed when traffic flows through a proxy. Every parameter is optional; omit one and the API's default applies. (Names follow each language's conventions, e.g. stickyMinutes / sticky_minutes / StickyMinutes.)
| Parameter | Type | What it does | |
|---|---|---|---|
protocol | "http" \ | "socks5" | Proxy protocol. Default http (which also carries HTTPS). Check plan.generate.protocols for what a product supports |
count | integer 1โ1000 | How many proxy lines to return. Default 1 | |
country | ISO 3166-1 alpha-2 | e.g. US, DE, JP. Omit for a worldwide IP | |
state | string | State or region, where the product supports it | |
city | string | City, where the product supports it | |
isp | string | Network / carrier, where the product supports it | |
stickyMinutes | integer | Keep the same IP for this many minutes. Omit for a fresh IP on every request. The maximum is plan.generate.maxStickyMinutes; 0 there means the product has no sticky sessions |
Each returned line is username:password@host:port with your targeting encoded in the username. Lines are on-demand and not persistent โ generate fresh ones when you need them instead of storing them, because credentials can rotate when the pool moves.
// Country, state and city โ what a plan supports is in plan.generate.targeting
await bp.plans.generate(plan.id, { country: "US", state: "California", city: "Los Angeles" });
// Sticky session: keep one IP for 30 minutes (max is plan.generate.maxStickyMinutes)
await bp.plans.generate(plan.id, { country: "DE", stickyMinutes: 30 });
// SOCKS5 instead of HTTP
await bp.plans.generate(plan.id, { protocol: "socks5", count: 10 });
// Bulk: up to 1000 lines per call
const { lines } = await bp.plans.generate(plan.id, { count: 1000 });
await fs.writeFile("proxies.txt", lines.join("\n"));Every top-up and allocation call takes a product key. Live prices come from the catalog call, so you never hard-code a rate.
| Key | Product | Min order | Best for |
|---|---|---|---|
residential | Core Residential | 1 GB | Everyday rotating residential IPs with country targeting |
premium | Premium Residential | 2 GB | City-level targeting, sticky sessions and priority routing |
isp | ISP Rotating | 1 GB | Datacenter speed with ISP-grade trust |
mobile | Mobile Proxies | 1 GB | Real carrier IPs for mobile-only targets |
ipv4 | Datacenter IPv4 | 1 GB | Fast, cheap per-GB datacenter traffic |
ipv6 | IPv6 Proxies | 1 GB | Huge address diversity at the lowest per-GB rate |
Pay-as-you-go top-ups of 100 GB or more include a 10% volume bonus, and a single order is capped at 10,000 GB.
Using the proxies with your stack
Each generated proxy is a small object (host, port, username, password, protocol) with helpers that return exactly what common clients expect, so you never hand-build a proxy URL or worry about percent-encoding special characters in a password.
Playwright
import { chromium } from "playwright";
const browser = await chromium.launch({ proxy: proxies[0].toPlaywright() });
const page = await browser.newPage();
await page.goto("https://api.ipify.org");Puppeteer
import puppeteer from "puppeteer";
const { args, credentials } = proxies[0].toPuppeteer();
const browser = await puppeteer.launch({ args });
const page = await browser.newPage();
await page.authenticate(credentials);Axios
import axios from "axios";
const { data } = await axios.get("https://api.ipify.org", { proxy: proxies[0].toAxios() });Node.js `fetch` / undici
import { ProxyAgent } from "undici";
const res = await fetch("https://api.ipify.org", { dispatcher: new ProxyAgent(proxies[0].url) });curl & shell
console.log(proxies[0].toCurl()); // curl -x 'http://user:pass@gw.buyproxy.org:6969' https://api.ipify.org
console.log(proxies[0].toEnv()); // { HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, โฆ }Account, balances & history
Read-only calls for building dashboards, alerts and pre-flight checks. balances is the one to watch: it shows spendable GB per product, including GB from a payment that's still being added (pending).
const catalog = await bp.products.list(); // product keys & live prices โ no API key needed
const account = await bp.account.get(); // email, plan, lifetime GB
const balances = await bp.balances.list(); // spendable GB per product (+ GB still arriving)
const plans = await bp.plans.list(); // plan ids and what each can generate
const history = await bp.transactions.list({ limit: 20 });Buying bandwidth
- Call the top-up method โ it returns a hosted payment URL and a transaction id. Card payments are processed by Stripe Checkout; crypto by an invoice page.
- Send your user (or yourself) to that URL to pay.
- Poll the transaction (or use the SDK's
waithelper) untilstatusissucceededorfailed. Crypto payments are checked live on every poll, so they settle even if a webhook is delayed. - The GB shows up under
balanceswithin seconds โpendingGbwhile it's arriving,activeGbonce it's live.
Plans are subscriptions billed monthly or yearly by card (crypto only covers pay-as-you-go top-ups). If the account already has a subscription, the call returns the subscription settings page as the URL and a null transaction id โ switching plans is prorated there, and you can't accidentally subscribe twice.
// Buy 10 GB of Core Residential by card โ open payUrl in a browser
const { payUrl, transactionId } = await bp.topup.card({ kind: "topup", productKey: "residential", gb: 10 });
// Or subscribe to a plan (monthly or yearly)
await bp.topup.card({ kind: "plan", plan: "pro", interval: "year" });
// Crypto (pay-as-you-go top-ups only)
await bp.topup.crypto({ productKey: "residential", gb: 50 });
// Wait for the payment to settle โ GB appears on bp.balances.list() right after
const tx = await bp.transactions.wait(transactionId!);
console.log(tx.status); // "succeeded"Card payments are processed by Stripe; crypto top-ups are pay-as-you-go only. Subscriptions can be managed or cancelled from Dashboard โ Billing.
Reseller API
The reseller API lets you build a proxy product on top of BuyProxy. The flow is always the same:
- Fund your pool โ buy GB per product into your reseller pool by card or crypto. Pool GB is priced like a normal top-up (including the volume bonus), fixed at purchase time.
- Create a customer โ an isolated sub-account with its own credentials and no bandwidth. Store the returned
username. - Allocate โ move whole GB of one product from your pool onto that customer, with an idempotency key. The first allocation of a product creates the plan; later ones add to it.
- Generate โ produce proxy lines for the customer from their plan id (found on the customer record), with all the usual targeting options.
- Monitor โ read the customer's usage (remaining, used, total per plan, plus any GB still arriving) to bill or alert.
- Suspend / reactivate โ a suspended customer can't generate new lines (
403). Lines already handed out may keep working until they rotate, so stop distributing them at the same time. You can also rename a customer.
Allocated GB can't be moved back to the pool, so allocate what a customer has paid for.
const reseller = new BuyProxy({ apiKey: process.env.BUYPROXY_RESELLER_KEY }); // bp_live_โฆ key
await reseller.reseller.pool.topupCard({ productKey: "residential", gb: 500 }); // buy into your pool
const customer = await reseller.reseller.customers.create({ label: "Acme Inc" }); // isolated sub-account
await reseller.reseller.customers.allocate(customer.username, {
productKey: "residential", gb: 20, idempotencyKey: "order-1042", // safe to retry
});
const { proxies } = await reseller.reseller.customers.generate(customer.username, {
planId: (await reseller.reseller.customers.get(customer.username)).plans[0].id,
country: "DE",
});
await reseller.reseller.customers.update(customer.username, { status: "suspended" });Allocating bandwidth to a customer moves real GB, so it accepts an idempotency key. Send the same key twice and the second call moves nothing and returns alreadyApplied: true with the same result โ safe to retry after a timeout or crash.
Use a value you can derive again from your own data (an order id, an invoice number), not a random value created per attempt. Keys are scoped to your account and may be up to 200 characters.
Errors & retries
Every non-success response becomes a typed error carrying the HTTP status and the API's own message, so you can branch on the failure instead of parsing strings.
| HTTP | Class | Meaning |
|---|---|---|
| 400 | ValidationError | A parameter was missing or invalid |
| 401 | AuthenticationError | Missing or invalid API key (also thrown locally when no key is set) |
| 402 | InsufficientBandwidthError | Empty reseller pool, or a plan with no GB left |
| 403 | PermissionError | Suspended account/customer, or the plan doesn't include this endpoint |
| 404 | NotFoundError | Plan, customer or transaction not found on this account |
| 429 | RateLimitError | Over 60 requests/minute โ has retryAfterSeconds |
| 5xx | ServerError | BuyProxy or an upstream provider is unavailable |
| โ | ConnectionError, TimeoutError | No response (DNS, reset, offline) / exceeded timeoutMs |
import { BuyProxy, AuthenticationError, InsufficientBandwidthError, RateLimitError } from "buyproxy";
try {
await bp.plans.generate(planId);
} catch (err) {
if (err instanceof InsufficientBandwidthError) console.log("Out of GB โ top up first");
else if (err instanceof RateLimitError) console.log(`Slow down; retry in ${err.retryAfterSeconds}s`);
else if (err instanceof AuthenticationError) console.log("Check your API key");
else throw err;
}Every error extends BuyProxyError and exposes status and the parsed body.
Every SDK retries for you, with the same rules:
- Rate limits (`429`) are always retried, waiting for the
Retry-Afterthe API sends (capped at 30 s) or an exponential back-off with jitter. - Reads (
GET) are also retried on502/503/504and on network failures. - Writes are not retried on server errors โ a repeated checkout or allocation must never double-charge โ unless you attach an idempotency key (see below), which makes the retry provably safe.
- The default is 2 retries; set it to 0 to turn retries off. After the last attempt you get the typed error.
The API allows 60 requests per minute per key. Batch with count (up to 1000 lines per call) rather than looping over single-proxy calls.
Configuration
new BuyProxy({
apiKey: "bp_key_โฆ", // default: process.env.BUYPROXY_API_KEY
baseUrl: "https://www.buyproxy.org",
timeoutMs: 30_000,
maxRetries: 2, // 429s always; 5xx only for safe requests
fetch: myFetch, // bring your own fetch
});Concurrency
// Everything is promise-based and safe to run in parallel (mind the 60 requests/minute limit)
const results = await Promise.all(plans.map((p) => bp.plans.generate(p.id, { count: 10 })));Testing your code
You don't need a real account or network to unit-test code that uses the SDK โ inject a fake transport. This is how the SDK's own test suite works.
import { BuyProxy } from "buyproxy";
// Inject a fake fetch โ no network, no mocking library
const bp = new BuyProxy({
apiKey: "bp_key_test",
fetch: async () =>
new Response(JSON.stringify({ lines: ["u:p@gw.buyproxy.org:6969"] }), {
status: 200,
headers: { "content-type": "application/json" },
}),
});
const { proxies } = await bp.plans.generate("plan_1");
expect(proxies[0].host).toBe("gw.buyproxy.org");API reference
Every method maps one-to-one onto a documented REST endpoint.
| Capability | Call |
|---|---|
| Catalog & prices | bp.products.list() |
| Account | bp.account.get() |
| Spendable GB per product | bp.balances.list() |
| Plans | bp.plans.list() |
| Generate proxies | bp.plans.generate(planId, params) |
| Card checkout | bp.topup.card(params) |
| Crypto checkout | bp.topup.crypto(params) |
| Payments | bp.transactions.list() ยท .get(id) ยท .wait(id) |
| Create an account | bp.auth.signup() ยท .verifyOtp() ยท .resendOtp() |
| Reseller summary | bp.reseller.me() |
| Customers | bp.reseller.customers.list/create/get/update/usage/allocate/generate |
| Reseller pool | bp.reseller.pool.get/topupCard/topupCrypto |
Notes
Zero runtime dependencies โ it uses the platform's
fetch.ProxyEndpointhas helpers for Playwright, Puppeteer, Axios, environment variables and curl.Every response and request type is exported, e.g.
import type { Plan, Balance, CustomerDetail } from "buyproxy".
Developing the SDK
npm install
npm run typecheck && npm test && npm run buildWas this page helpful?