Wholesale Reseller API
This API lets wholesale proxy resellers buy and manage shared proxies programmatically — using the same engine and pricing our store uses, plus a fixed per-reseller discount. Every request runs through the exact same purchase engine that manual orders use.
Quick start
- Create an account and contact support to enable reseller mode and set your discount.
- Get your API key from support.
- Use the endpoints below — each operation has its own HTTP method and path.
- Top up your balance — each purchase or extension is debited from it.
Base URL & authentication
All paths under /api/reseller/v1/* require the X-API-Key header. Keep your key secret — any request with an invalid key is rejected with 401.
Period values
The "period" field accepts five values: 3h (3 hours), 12h (12 hours), 24h (a day), 7d (a week), 30d (a month).
Pricing & discount
Prices returned by /pools are the final, post-discount prices — exactly what is debited. For create and extend the amount is debited before execution and fully auto-refunded on failure.
Webhook setup (step-by-step)
Webhooks notify your app of every account event (unit created / extended / released / swapped, usage warning, throttle, unit down, balance low). Setup happens through the API itself:
- Stand up a public HTTPS endpoint on your server that accepts a JSON POST.
- Call PATCH /api/reseller/v1/webhook with { "url": "<your endpoint>" }. The response includes a secret — store it immediately (not shown again).
- On every incoming request: verify the X-WTProxy-Signature header using HMAC-SHA256 of the raw body with the secret. Reject anything that doesn't match.
- Return 2xx fast (< 5s). Any error or timeout schedules an exponential retry (1m → 5m → 30m → 2h → 6h, up to 6 attempts).
- Inspect the delivery log via GET /api/reseller/v1/webhook/deliveries — shows every event's status (delivered/pending/failed) and reason.
The events your endpoint will receive:
| Event | Fires when | Key data fields |
|---|---|---|
unit.created | A unit is purchased | proxyRef, poolId, period, pricePaid |
unit.extended | A unit is extended | proxyRef, period, pricePaid, expiresAt |
unit.swapped | A unit is moved to another server | proxyRef |
unit.protocol_changed | Protocol/encryption changed | proxyRef |
unit.modified | Credentials/whitelist modified | proxyRef |
unit.released | A unit is released | proxyRef |
unit.down | A unit stops unexpectedly: data cap or server unreachable | proxyRef, reason (quota_exceeded | server_unreachable) |
usage.warning | 80% throttle / 75% delete of the daily cap | proxyRef, kind, thresholdPct, consumedMb, limitMb |
usage.throttled | A unit is speed-limited for exceeding data | proxyRef, throttleSpeedMbps, durationHours, consumedMb, limitMb |
server.down | Admin flagged a whole server as down | poolCode, reason, affectedUnits[] |
server.ip_changed | Server host IP changed (redeploy) | poolCode, newIp, oldIp?, affectedUnits[] |
balance.low | Your wallet drops below the threshold | balance, threshold |
Every payload has the shape { event, occurredAt, data }. The fields under data are shown above.
Headers sent with every webhook:
X-WTProxy-EventEvent name, e.g. unit.created.X-WTProxy-DeliveryUnique delivery id per attempt (use for idempotency on your side).X-WTProxy-TimestampSend time (unix seconds).X-WTProxy-Signaturesha256=<HMAC of body with secret>. Verify before trusting the payload.
Node.js verification example:
import crypto from 'crypto';
app.post('/wtproxy-events', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.header('X-WTProxy-Signature') || '';
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WTPROXY_WEBHOOK_SECRET)
.update(req.body) // raw body, before JSON.parse
.digest('hex');
if (sig !== expected) return res.sendStatus(401);
const event = JSON.parse(req.body.toString());
// event = { event: 'unit.created', occurredAt: '...', data: {...} }
res.sendStatus(200); // ack within 5s
});Connection fields — what they mean
ipThe proxy IP address the client connects to.portThe port number used for the connection.usernameThe username for proxy authentication.passwordThe password for proxy authentication.protocolProtocol: socks5 / http / inject — where inject = HTTP No Auth via IP whitelist.poolIdPool (server) ID, e.g. "US-12".providerThe network provider, e.g. T-Mobile.proxyRefThe unique proxy reference in the form "PRX-{n}".expiresAtExpiry date & time (ISO 8601).
Pagination
Endpoints that return large lists (e.g. /units) are paginated. Items come under "data"; paging metadata under the "pagination" object. Control it with the page and pageSize query parameters.
pageCurrent page number (1-based).pageSizeItems per page (default 50, max 200).totalItemsTotal number of items across all pages.totalPagesTotal number of pages = ceil(totalItems / pageSize).hasNexttrue if a next page exists.hasPrevtrue if a previous page exists.
Error handling
Every error returns a uniform "error" object. Branch on error.type and error.code (both stable, machine-readable); error.message is for display only. Each error carries a requestId — quote it when contacting support.
authentication_error401Missing or invalid API key.permission_error403The account lacks reseller permission.invalid_request_error400A malformed body, field, or value.not_found_error404The requested resource does not exist.insufficient_balance_error402Balance below the required amount (see error.required).rate_limit_error429Request rate limit exceeded.service_error5xxA temporary service error — retry.
Rate limits
Each key has two budgets: an account-wide one for the whole API, and a tighter one on a few heavy endpoints. They are independent — exhausting an endpoint’s budget does not block the others. Over the limit the API returns 429 with error.code = rate_limited and a Retry-After header: wait that long rather than retrying immediately.
Whole API (per key)120 / minThe account-wide budget for any /api/reseller/v1 request.GET /me/uptime10 / minIts own budget: one call aggregates thousands of probe readings. Exceeding it does not block the rest of the API.
Headers on every response
X-RateLimit-LimitThe ceiling for the current window.X-RateLimit-RemainingHow many requests you have left in this window.X-RateLimit-ResetWhen the window resets (unix seconds).Retry-AfterOn 429 only: how many seconds to wait before retrying.
Changelog
The most recent additions to the API. Additions are always backwards-compatible: new fields may appear in responses, so make your parser ignore what it does not recognise.
2026-07-31New: GET /me/uptime — account-wide uptime with a per-unit breakdown (10 req/min).2026-07-31Documented: GET /countries and GET /states were live but undocumented — both are now here.2026-07-31Documented: a Rate limits section with the real numbers and headers, and {proxyRef} unified across every path example.
List available pools
Returns every available pool (Pro only), with all five discounted period prices. Filterable by provider or country.
Query parameters
providerstringoptionalOptional — filter by carrier (e.g. "T-Mobile", "Verizon", "AT&T").countrystringoptionalOptional — filter by country slug.
Single pool detail
Returns one pool's detail with its own discounted prices.
Path parameters
poolIdstringrequiredPool ID (e.g. "US-1").
Price schedule
Returns the five period prices (post-discount) — quick lookup separate from the pool list.
List providers
Returns the distinct carriers in the catalogue (T-Mobile, Verizon, AT&T, …) with the number of pools per provider. Use this to power a carrier filter in your UI.
List countries
Countries available in the catalogue with the number of pools in each. Codes are ISO — the same value you later pass as "country" when provisioning.
List states
States/regions in the catalogue with pool counts, optionally narrowed to one country via the country parameter. Use it to build a cascading picker: country → state → pool.
Query parameters
countrystringoptionalRestrict to a single country (ISO code, e.g. US).
List your units (paginated)
Returns the proxies your account owns, sorted by poolId. Supports pagination and filters.
Query parameters
includeExpiredbooleanoptionalOptional — true to also include expired units.statusstringoptionalOptional — exact status filter (ACTIVE / EXPIRED / RELEASED).poolIdstringoptionalOptional — only units from this pool.expiringWithinHoursintegeroptionalOptional — only units expiring within N hours.pageintegeroptionalOptional — page number (default 1).pageSizeintegeroptionalOptional — page size (default 50, max 200).
Single unit detail
Returns the details of a specific proxy you own.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-9").
Unit usage
Returns a specific proxy’s consumption with the same numbers the customer app shows. Short plans (POOL: 3h/12h/24h) report plan quota vs used and remaining (mode="pool"). Long plans (weekly/monthly) report today’s usage vs the daily limit (mode="daily"), with the lifetime figure in totalMb.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-9").
Create a new unit
Buys a new proxy from the chosen pool. The discounted price is debited from your balance, and auto-refunded on failure. Send an Idempotency-Key header (a UUID) to guarantee a retry after a network failure never double-charges or double-provisions. The key is honoured for 24 hours: a retry within that window replays the original result, a still-in-flight duplicate gets HTTP 409, and after 24 hours the key is treated as a fresh request.
Request body fields (JSON)
poolIdstringrequiredThe pool ID from /pools (e.g. "US-12").periodstringrequiredPeriod: 3h, 12h, 24h, 7d, 30d.protocolstringoptionalOptional — socks5 (default) or http (both use username/password) or inject (HTTP No Auth, IP whitelisted).credentialsobjectoptionalOptional — { username, password } for custom credentials.allowedIpsstring[]optionalRequired when protocol="inject" — at creation it must contain exactly ONE IP. Additional IPs are added later via PATCH on the unit.
Extend a unit
Extends a proxy by another period. The discounted price is debited and refunded on failure.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-12345").
Request body fields (JSON)
periodstringrequiredPeriod to add: 3h, 12h, 24h, 7d, 30d.
Swap pool
Moves the proxy to another pool while keeping its remaining time. No balance is charged.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-12345").
Request body fields (JSON)
newPoolIdstringrequiredThe ID of the new pool.
Change protocol (encryption)
Switches the encryption protocol (socks5 ↔ http ↔ http_noauth) while keeping the same proxyRef, remaining time, speed throttle, and consumption history. No balance is charged.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-12345").
Request body fields (JSON)
newProtocolstringrequiredThe new protocol. One of: "socks5" | "http" | "http_noauth". Must differ from the current value.credentialsobjectoptionalOptional for socks5/http (reuses existing credentials when omitted). Ignored for http_noauth. Shape: { "username": "...", "password": "..." }.allowedIpsstring[]optionalRequired when newProtocol = "http_noauth" — exactly one client IP to whitelist. Additional IPs can be added later via PATCH /units/{id}.
Modify a unit
Updates credentials, description, or the allowed-IP list.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-12345").
Request body fields (JSON)
credentialsobjectoptionalOptional — new { username, password }.descriptionstringoptionalOptional — a new description.allowedIpsstring[]optionalOptional — a new allowed-IP list.
Release a unit
Permanently deletes the proxy. No balance is refunded for a manual release.
Path parameters
proxyRefstringrequiredThe proxy reference (e.g. "PRX-12345").
Account snapshot
Everything you need on session start in one round-trip: balance, discount, unit counts, prices, webhook status.
Account uptime
Uptime across all your units plus a per-unit breakdown. Measured from a probe every 5 minutes per pool — each probe is one "slot", so a full day is 288. Every unit is scored over its OWN lifetime inside the window, so a unit created today is not charged for yesterday. Only up/down readings count; probes that could not reach the provider API are excluded — that is our monitoring failing, not downtime you lived through. Defaults to the last 24 hours, capped at 30 days.
Query parameters
dayintegeroptionalWindow length in days (1–30) counted back from now. Default 1. Ignored when from/to are supplied.fromstringoptionalWindow start (ISO-8601). Defaults to 24h ago.tostringoptionalWindow end (ISO-8601). Clamped to now.
Query balance
Returns the current balance and the discount rate applied to your purchases.
Pin a fixed proxy username
Pins one username to be used on every unit you create afterwards. Without it each proxy gets a random login, so your customers receive different credentials for every unit. Send null to go back to a generated login per unit. Applies to NEW units only — units already provisioned keep their credentials. The password stays per-unit on purpose: pinning it too would mean one leaked pair opens every unit you own. A per-request credentials object still overrides this.
Request body fields (JSON)
proxyUsernamestring | nullrequired3–32 characters, no spaces, ":" or "@". Send null to clear it.
Read current webhook config
Returns the currently configured webhook URL, the HMAC secret, and the enabled flag. If no webhook is set, all fields are null/false.
Configure webhook
Sets the webhook URL for account events (create / extend / release / low balance). The HMAC secret is returned once — use it to verify the X-WTProxy-Signature header on incoming requests. Pass url=null to disable.
Request body fields (JSON)
urlstringoptionalHTTPS URL to receive events, or null to disable.
Send a test event
Fires a sample unit.created event at your registered URL through the real delivery pipeline (same signature, same retry policy), with test: true in the payload. Use it to prove your receiver is reachable and your signature check works before the first real event. Watch the outcome via GET /webhook/deliveries.
Webhook delivery log
Lists recent webhook delivery attempts (success/failure/pending retry) for debugging. Newest first. Supports filtering by status and event.
Query parameters
pageintegeroptionalPage number (default 1).pageSizeintegeroptionalItems per page (default 25, max 100).statusstringoptionalFilter by status: PENDING / DELIVERED / FAILED.eventstringoptionalFilter by event type (e.g., unit.created, unit.released).
Disable webhook
Removes the webhook URL and secret. No further notifications will be delivered until you set it again via PATCH.