Overview
Getting access. The reseller API is enabled once your reseller account is activated. You then create an API key and call the endpoints below with it.
Bandwidth poolYour prepaid balance. Allocating to a sub-account draws from it; reclaiming returns to it.
Sub-accountsEach of your end-customers is a sub-account with its own bandwidth, proxy credentials and usage.
https://app.nefo.net/api/v1/resellerProducts
You can sell three products. Each has its own pool, its own wholesale rate and its own balance on every sub-account, so a GB of one is never spent as another. Pick one with the product field on allocate, proxies, usage and locations.
| product | Product | Targeting | Sticky IP |
|---|---|---|---|
| residential | Rotating residential | Country, state, city, ASN | 1–1440 min |
| datacenter | Rotating datacenter | Country, city, ASN | 1–1440 min |
| mobile_rotating | Rotating mobile (4G/5G carrier IPs) | Country; state, city and ASN count traffic twice | 1–120 min |
Leave product out and every call means residential, exactly as before. Datacenter and rotating mobile are available once they are enabled on your account — until then those calls answer 403 product_not_enabled.
# Allocate 10 GB of DATACENTER to a sub-account
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/allocate" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"gb": 10, "product": "datacenter"}'
# Generate a ROTATING MOBILE proxy for it
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"product": "mobile_rotating", "country": "us",
"protocol": "http", "sessionMode": "rotating"}'
# No "product" = residential, exactly as beforePools
Residential bandwidth works on all three pools at the same price. Send pool with POST /proxies to choose one; leave it out for Pool 1, exactly as before. A Mix spreads requests across the pools in mixPools, in equal shares. A pool that can't serve the target sits out, and a target only one pool serves runs on Pool 1: each line's pool, mixPools and poolNote say what it runs on.
| pool | Targeting | Sticky | |
|---|---|---|---|
| 1 | Pool 1 | Country, state, city and ISP (ASN), combined freely | 1–1440 min |
| 2 | Pool 2 | Country, then one of: a state, a city or an ISP | 1–60 min |
| 3 | Pool 3 | Country; state and city in the US | 1–1440 min |
| mix | Mix | Pool 1's places; each pool in the Mix serves what it can | 1–1440 min with Pools 1 + 3 (Pool 2 sits out past 60); 1–60 min otherwise |
Places for Pool 2 and Pool 3: GET /locations?pool=2 (or 3). Names work as well as codes: "Los Angeles", "losangeles" and "los_angeles" are the same city.
# Pool 3, Los Angeles, the same IP for 30 minutes
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"pool": "3", "protocol": "http", "country": "us",
"state": "california", "city": "losangeles",
"sessionMode": "sticky", "stickyDurationMinutes": 30}'
# A Mix of all three pools, a new IP on every request
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"pool": "mix", "mixPools": "123", "protocol": "http",
"country": "gb", "sessionMode": "rotating", "count": 5}'
# Pool 2's own states, cities and ISPs in one country
curl "https://app.nefo.net/api/v1/reseller/locations/GB?pool=2" \
-H "Authorization: Bearer sk_live_xxx"Authentication
Every request is authenticated with your API key as a Bearer token. Keep it secret — it can provision bandwidth from your pool.
Rate limit: 120 requests per minute per key (proxy generation is throttled further). Keep your key secret and server-side.
GET /api/v1/reseller/pool HTTP/1.1
Host: nefo.net
Authorization: Bearer sk_live_xxxErrors
Errors return a JSON body { "error": { "code", "message" } } with the matching HTTP status:
| Status | Meaning |
|---|---|
| 400 | Invalid request body or parameters |
| 401 | Missing, invalid or revoked API key |
| 402 | Insufficient bandwidth balance to generate proxies |
| 403 | API key is missing the required scope |
| 404 | Not found, or not yours. |
| 422 | Sub-account limit reached. |
| 429 | Rate limit exceeded — see Retry-After header |
| 503 | The product is under maintenance. Try again shortly. |
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"error": {
"code": "insufficient_pool",
"message": "…"
}
}Self-serve session IDs
Every credential's username is just a token string, and its password stays the same for the sub-account's whole life. Once you've generated one, build as many rotating or sticky sessions as you want locally — no extra API calls, no 20-per-request batch limit.
Sessions built this way aren't tracked as individual credentials — they won't show up in a sub-account's proxy list and can't be revoked one by one. Bandwidth is still enforced correctly against your allocation either way, and aggregate usage still shows via the usage endpoint.
# Base credential, from any POST …/proxies call
username: acme-country-us
password: 3f9c2a1b-7e4d-4a2c-9f1a-8b6c5d4e3f2a
# Rotating: no session token, a fresh IP every request
acme-country-us
# Sticky: append your own session id + lifetime (1-1440 minutes).
# Build as many as you want locally, no API call needed:
acme-country-us-session-req0001-lifetime-30
acme-country-us-session-req0002-lifetime-30
acme-country-us-session-req0003-lifetime-30
# State and city targeting work the same way (see /locations):
acme-country-us-state-california-session-req0004-lifetime-30White-labeling your gateway
Route proxies through your own domain instead of ours. gatewayId picks the entry region (fr/us/sg) — it doesn't affect exit country, which you set separately via the country field.
| Region | gatewayId | CNAME target |
|---|---|---|
| Nearest (default) | auto | gw.nefo.net |
| France | fr | fr.nefo.net |
| United States | us | us.nefo.net |
| Singapore | sg | sg.nefo.net |
- 1Add a DNS record.For each region you want branded, create a
CNAMEfrom your own subdomain (e.g.us.yourbrand.com) to that region's target above. Only set up the regions you'll use; anything left blank falls back to your default host. If your DNS provider can't do a CNAME there, use anArecord and ask us for the current IPs. A CNAME follows automatically if they change; an A record won't. - 2Wait for DNS to propagate.Usually a few minutes, sometimes a few hours, depending on your provider and TTL.
- 3Set it in your dashboard.Go to Reseller → White-label gateway. With more than one region you'll see a field per region plus a Default field. Enter the domain you set up and save.
- 4Verify.Generate a test proxy for that region, check that the
hostin the response is your domain, then connect through it once.
gatewayIdpicks your customer's entry point, not their exit country; the exit country is the country field. A DNS lookup on your CNAME still shows it resolves to nefo.net. To hide that from your own customers, run your own relay (nginx or HAProxy stream) in front instead of a plain CNAME, and ask us if you need help.
; One CNAME per region you brand
proxy.yourbrand.com. CNAME gw.nefo.net.
fr.yourbrand.com. CNAME fr.nefo.net.
us.yourbrand.com. CNAME us.nefo.net.
sg.yourbrand.com. CNAME sg.nefo.net.Reseller API endpoints
Get your bandwidth pool balance
GET/pool
Scope: reseller:read
No parameters.
curl "https://app.nefo.net/api/v1/reseller/pool" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"poolGb": 812.5,
"allocatedGb": 187.5,
"subAccounts": 42,
"products": {
"residential": { "poolGb": 812.5, "allocatedGb": 187.5, "ratePerGb": 0.54, "pricing": "wholesale" },
"datacenter": { "poolGb": 300, "allocatedGb": 23.2, "ratePerGb": null, "pricing": "site" }
}
}Create a sub-account for one of your customers
POST/subaccounts
Scope: reseller:manage
Body parameters
labelstringOptionalYour name for this customer, up to 80 characters.
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"label": "customer-acme"
}'Response201
{
"id": "sub_9f2a…",
"label": "customer-acme",
"balanceGb": 0,
"usedGb": 0,
"status": "active",
"createdAt": "2026-09-30T08:12:44.000Z",
"products": {
"residential": { "balanceGb": 8.4, "usedGb": 1.6 },
"datacenter": { "balanceGb": 20, "usedGb": 3.2 },
"mobile_rotating": { "balanceGb": 0, "usedGb": 0 }
}
}List your sub-accounts with balance and usage
GET/subaccounts
Scope: reseller:read
No parameters.
curl "https://app.nefo.net/api/v1/reseller/subaccounts" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"data": [
{
"id": "sub_9f2a…",
"label": "customer-acme",
"balanceGb": 8.4,
"usedGb": 1.6,
"status": "active",
"createdAt": "2026-09-30T08:12:44.000Z",
"products": {
"residential": { "balanceGb": 8.4, "usedGb": 1.6 },
"datacenter": { "balanceGb": 20, "usedGb": 3.2 },
"mobile_rotating": { "balanceGb": 0, "usedGb": 0 }
}
}
]
}Get one sub-account
GET/subaccounts/{id}
Scope: reseller:read
Path parameters
idstringRequiredThe sub-account's id.
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"id": "sub_9f2a…",
"label": "customer-acme",
"balanceGb": 8.4,
"usedGb": 1.6,
"status": "active",
"createdAt": "2026-09-30T08:12:44.000Z",
"products": {
"residential": { "balanceGb": 8.4, "usedGb": 1.6 },
"datacenter": { "balanceGb": 20, "usedGb": 3.2 },
"mobile_rotating": { "balanceGb": 0, "usedGb": 0 }
}
}Rename a sub-account or reactivate it
PATCH/subaccounts/{id}
Scope: reseller:manage
Path parameters
idstringRequiredThe sub-account's id.
Body parameters
labelstring | nullOptionalYour name for this customer, up to 80 characters.reactivatebooleanOptionaltrue re-enables the sub-account's proxies. Bandwidth is not restored.
curl -X PATCH "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"label": "customer-acme-eu"
}'Response200
{
"id": "sub_9f2a…",
"label": "customer-acme-eu",
"balanceGb": 8.4,
"usedGb": 1.6,
"status": "active",
"createdAt": "2026-09-30T08:12:44.000Z",
"products": {
"residential": { "balanceGb": 8.4, "usedGb": 1.6 },
"datacenter": { "balanceGb": 20, "usedGb": 3.2 },
"mobile_rotating": { "balanceGb": 0, "usedGb": 0 }
}
}Allocate bandwidth to a sub-account from your pool
POST/subaccounts/{id}/allocate
or send a negative gb to reclaim it back.
Scope: reseller:manage
Path parameters
idstringRequiredThe sub-account's id.
Body parameters
gbnumberRequiredGB to move from your pool. A negative number moves GB back, up to the sub-account's balance.productstringOptionalWhich product: residential (default), datacenter or mobile_rotating. Each has its own pool, wholesale rate and sub-account balance, and is available once it is enabled on your account.residentialdatacentermobile_rotatingDefault:residential
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/allocate" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"gb": 10,
"product": "datacenter"
}'Response200
{
"id": "sub_9f2a…",
"product": "datacenter",
"balanceGb": 10,
"poolGb": 290
}
// With a negative gb:
// { "id": "sub_9f2a…", "product": "datacenter", "reclaimedGb": 4, "balanceGb": 6, "poolGb": 294 }Generate proxy credentials for a sub-account
POST/subaccounts/{id}/proxies
rotating (new IP per request) or sticky (same IP for 1–1440 minutes via stickyDurationMinutes).
Scope: reseller:manage
Path parameters
idstringRequiredThe sub-account's id.
Body parameters
productstringOptionalWhich product: residential (default), datacenter or mobile_rotating. Each has its own pool, wholesale rate and sub-account balance, and is available once it is enabled on your account. For mobile_rotating, country targeting is the default; state, city and ASN targeting count traffic twice, and a sticky IP is held for at most 120 minutes.residentialdatacentermobile_rotatingDefault:residentialprotocolstringRequiredProtocol the credentials speak.httpsocks5countrystringRequiredTwo-letter country code, or ANY for worldwide.statestringOptionalUS state, full name without spaces, e.g. california.citystringOptionalCity name without spaces, e.g. losangeles. Ignored when asn is set.asnintegerOptionalISP network number, e.g. 7922 for Comcast.sessionModestringRequiredrotating gives a new IP on every request; sticky keeps one IP for stickyDurationMinutes.rotatingstickystickyDurationMinutesintegerOptionalHow long a sticky IP is held, 1–1440 minutes. Required when sessionMode is sticky.countintegerOptionalHow many credentials to create, 1–20.Default:1labelstringOptionalYour name for them, up to 80 characters. With count above 1 each one gets #n.gatewayIdstringOptionalEntry region: fr, us or sg. It picks which of your white-label hosts is returned.frussgpoolstringOptionalResidential pool: 1 (default), 2, 3 or mix. See Pools.123mixDefault:1mixPoolsstringOptionalWith pool mix: the pools it draws on, 12, 13, 23 or 123 (default 123).121323123Default:123strictbooleanOptionaltrue: only the exact state, city or ISP; false: fall back to the country when it has no free IP. Default true on Pool 1 and false on a Mix; a strict Mix runs on Pool 1.
curl -X POST "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"country": "us",
"protocol": "http",
"sessionMode": "rotating",
"gatewayId": "us"
}'Response201
{
"data": [
{
"id": "clx…",
"host": "gw.your-brand.com",
"port": 9000,
"username": "acme-country-us",
"password": "…",
"protocol": "http",
"country": "us",
"state": null,
"city": null,
"sessionMode": "rotating",
"stickyDurationMinutes": null,
"label": "customer-acme",
"product": "residential",
"pool": "1",
"mixPools": null,
"poolNote": null
}
]
}List a sub-account's proxy credentials, passwords included
GET/subaccounts/{id}/proxies
Scope: reseller:read
Path parameters
idstringRequiredThe sub-account's id.
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"data": [
{
"id": "clx…",
"host": "gw.your-brand.com",
"port": 9000,
"username": "acme-country-us",
"password": "…",
"protocol": "http",
"country": "us",
"state": null,
"city": null,
"sessionMode": "rotating",
"stickyDurationMinutes": null,
"label": "customer-acme",
"status": "active",
"createdAt": "2026-09-30T08:12:44.000Z",
"lastUsedAt": null,
"product": "residential",
"pool": "1",
"mixPools": null,
"poolNote": null
}
]
}Get a sub-account's usage over a date range
GET/subaccounts/{id}/usage
Scope: reseller:read
Path parameters
idstringRequiredThe sub-account's id.
Query parameters
rangestringOptionalTime window. An unknown value falls back to 24h.1h24h7d30d90dtodaymonth12mallDefault:24hproductstringOptionalWhich product: residential (default), datacenter or mobile_rotating. Each has its own pool, wholesale rate and sub-account balance, and is available once it is enabled on your account.residentialdatacentermobile_rotatingDefault:residential
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/usage?range=30d" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"product": "residential",
"range": "30d",
"totalGb": 6.8,
"totalRequests": 91240,
"successRate": 98.7,
"series": [{ "period": "2026-09-01", "gb": 0.4 }],
"requestSeries": [ … ]
}Deactivate a sub-account and reclaim its remaining bandwidth
DELETE/subaccounts/{id}
Scope: reseller:manage
Path parameters
idstringRequiredThe sub-account's id.
curl -X DELETE "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"id": "sub_9f2a…",
"status": "deactivated",
"reclaimedGb": 8.4,
"reclaimed": { "residential": 8.4, "datacenter": 20, "mobile_rotating": 0 }
}List all targetable countries
GET/locations
Scope: reseller:read
Query parameters
productstringOptionalWhich product: residential (default), datacenter or mobile_rotating. Each has its own pool, wholesale rate and sub-account balance, and is available once it is enabled on your account.residentialdatacentermobile_rotatingDefault:residentialpoolstringOptionalResidential pool whose places to list: 1 (default), 2 or 3. A Mix targets with Pool 1's list.123Default:1
curl "https://app.nefo.net/api/v1/reseller/locations" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"product": "residential",
"data": [
{ "code": "US", "name": "United States" },
{ "code": "GB", "name": "United Kingdom" }
]
}Get one country's states, cities, and ISPs/ASNs
GET/locations/{country}
Scope: reseller:read
Path parameters
countrystringRequiredTwo-letter country code.
Query parameters
productstringOptionalWhich product: residential (default), datacenter or mobile_rotating. Each has its own pool, wholesale rate and sub-account balance, and is available once it is enabled on your account.residentialdatacentermobile_rotatingDefault:residentialpoolstringOptionalResidential pool whose places to list: 1 (default), 2 or 3. A Mix targets with Pool 1's list.123Default:1
curl "https://app.nefo.net/api/v1/reseller/locations/US" \
-H "Authorization: Bearer sk_live_xxx"Response200
{
"product": "residential",
"data": {
"states": [
{
"code": "california",
"name": "California",
"cities": [{ "code": "losangeles", "name": "Los Angeles" }]
}
],
"asns": [{ "code": "7922", "name": "Comcast Cable Communications, LLC" }]
}
}Become a reseller
The reseller API is enabled once your reseller account is activated. Read the reseller program overview for how wholesale pricing works, or apply directly.
Frequently asked questions
The API is enabled once your reseller account is activated. After that you create an API key and call the endpoints with it as a Bearer token. Start on the reseller program page.
120 requests per minute per key, and proxy generation is throttled further. Exceeding it returns 429 with a Retry-After header. Keep the key secret and server-side.
Yes. After generating one credential, build as many rotating or sticky sessions as you want locally by changing the session token in the username. These sessions are not tracked individually, but bandwidth is still enforced against the allocation.
Create a CNAME from your subdomain to the regional target, such as us.nefo.net, wait for DNS, set the domain in Reseller, White-label gateway in the dashboard, and verify with a test proxy. The section above has the full steps.
Rotating residential, rotating datacenter and rotating mobile (4G/5G carrier IPs). Send the product field on allocate, proxies, usage and locations. Leaving it out means residential.