Skip to content
Nefo

Developers

Reseller API reference for proxy sub-accounts

Provision proxies for your customers programmatically: create sub-accounts, allocate bandwidth, generate credentials and read usage with a Bearer API key.

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.

shell
https://app.nefo.net/api/v1/reseller

Products

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.

productProductTargetingSticky IP
residentialRotating residentialCountry, state, city, ASN1–1440 min
datacenterRotating datacenterCountry, city, ASN1–1440 min
mobile_rotatingRotating mobile (4G/5G carrier IPs)Country; state, city and ASN count traffic twice1–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.

shell
# 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 before

Pools

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.

poolTargetingSticky
1Pool 1Country, state, city and ISP (ASN), combined freely1–1440 min
2Pool 2Country, then one of: a state, a city or an ISP1–60 min
3Pool 3Country; state and city in the US1–1440 min
mixMixPool 1's places; each pool in the Mix serves what it can1–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.

shell
# 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.

shell
GET /api/v1/reseller/pool HTTP/1.1
Host: nefo.net
Authorization: Bearer sk_live_xxx

Errors

Errors return a JSON body { "error": { "code", "message" } } with the matching HTTP status:

StatusMeaning
400Invalid request body or parameters
401Missing, invalid or revoked API key
402Insufficient bandwidth balance to generate proxies
403API key is missing the required scope
404Not found, or not yours.
422Sub-account limit reached.
429Rate limit exceeded — see Retry-After header
503The product is under maintenance. Try again shortly.
shell
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.

shell
# 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-30

White-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.

RegiongatewayIdCNAME target
Nearest (default)autogw.nefo.net
Francefrfr.nefo.net
United Statesusus.nefo.net
Singaporesgsg.nefo.net
  1. 1Add a DNS record.For each region you want branded, create a CNAME from 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 an Arecord and ask us for the current IPs. A CNAME follows automatically if they change; an A record won't.
  2. 2Wait for DNS to propagate.Usually a few minutes, sometimes a few hours, depending on your provider and TTL.
  3. 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.
  4. 4Verify.Generate a test proxy for that region, check that the host in 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.

shell
; 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.

shell
curl "https://app.nefo.net/api/v1/reseller/pool" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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.
shell
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

shell
{
  "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.

shell
curl "https://app.nefo.net/api/v1/reseller/subaccounts" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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.
shell
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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.
shell
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

shell
{
  "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
shell
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

shell
{
  "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: residential
  • protocolstringRequiredProtocol the credentials speak.httpsocks5
  • countrystringRequiredTwo-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.rotatingsticky
  • stickyDurationMinutesintegerOptionalHow long a sticky IP is held, 1–1440 minutes. Required when sessionMode is sticky.
  • countintegerOptionalHow many credentials to create, 1–20.Default: 1
  • labelstringOptionalYour 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.frussg
  • poolstringOptionalResidential pool: 1 (default), 2, 3 or mix. See Pools.123mixDefault: 1
  • mixPoolsstringOptionalWith pool mix: the pools it draws on, 12, 13, 23 or 123 (default 123).121323123Default: 123
  • strictbooleanOptionaltrue: 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.
shell
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

shell
{
  "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.
shell
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/proxies" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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: 24h
  • 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
shell
curl "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID/usage?range=30d" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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.
shell
curl -X DELETE "https://app.nefo.net/api/v1/reseller/subaccounts/SUB_ID" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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: residential
  • poolstringOptionalResidential pool whose places to list: 1 (default), 2 or 3. A Mix targets with Pool 1's list.123Default: 1
shell
curl "https://app.nefo.net/api/v1/reseller/locations" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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: residential
  • poolstringOptionalResidential pool whose places to list: 1 (default), 2 or 3. A Mix targets with Pool 1's list.123Default: 1
shell
curl "https://app.nefo.net/api/v1/reseller/locations/US" \
  -H "Authorization: Bearer sk_live_xxx"

Response200

shell
{
  "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.

Start with 5 GB. Keep what you don't use.

Residential bandwidth from $0.53/GB that never expires. Card, PayPal, Apple Pay, Google Pay, Alipay and crypto.