Live API Origin: Β·
High-performance REST API with SOCKS5 & HTTP/HTTPS proxy gateways. Full client-side offline demo mode supported.
GET /api/health
Response: { "ok": true, "mode": "server", "name": "OwllProxy" }
Bearer Token or Session cookie np_token. This site is owner-only β signup and instant demo accounts are closed, and only the admin account can sign in.
POST/api/auth/signup { "email", "password" } β 403 (signup closed β owner-only site) POST/api/auth/instant { } β 403 (closed β owner-only site) POST/api/auth/login { "email", "password" } β Owner / admin login only POST/api/auth/logout GET /api/me β Current user object & remaining balance
Rate: 10MB per line (0.01 GB). Supports country, state, city filtering, rotation, and protocol selection.
POST/api/extract
Payload:
{
"country": "US",
"state": "California",
"city": "Los Angeles",
"protocol": "socks5",
"rotation": "10min",
"format": "hpu",
"qty": 5
}
Response (200 OK):
{
"lines": [
"104.16.240.54:7777:np_user_session_abc123:pass456"
],
"cost": 0.05,
"trafficGB": 0.05,
"balanceMB": 50
}
Every member is issued one forwarding key automatically at sign-up (visible in Dashboard β API & Forwarding). The site also carries its own master forwarding key, so a request can be relayed on behalf of a named member. In both cases the transfer is measured byte-by-byte and charged against that member's ceiling β the key never grants extra traffic.
POST/api/forward Relay one request. Body: { "key", "url", "method", "headers", "body", "member" } GET /api/plan Your ceiling, used MB, remaining MB + key list GET /api/keys My API keys (label, quota, metered bytes, request count) POST/api/keys/rotate Replace my key β the previous one stops working instantly GET /api/usage Metered request log (last 100 calls)
curl -X POST https://owlproxy.pro/api/forward \
-H "Content-Type: application/json" \
-d '{
"key": "npk_β¦your-key-from-the-boardβ¦",
"member": "alice@example.com",
"url": "https://api.ipify.org?format=json",
"method": "GET"
}'
# β { "mode": "browser-relay", "upstream_status": 200, "bytes": 26,
# "quota": { "limitMB": 100, "usedMB": 0.002, "leftMB": 99.998 },
# "preview": "{\"ip\": \"...\"}" }
# Member key instead (no "member" field needed):
curl -X POST https://owlproxy.pro/api/forward \
-H "Content-Type: application/json" \
-d '{ "key": "npk_β¦your-member-keyβ¦", "url": "https://example.com/target" }'
import requests
SITE = "https://owlproxy.pro"
r = requests.post(f"{SITE}/api/forward", json={
"key": "npk_β¦your-key-from-the-boardβ¦",
"member": "alice@example.com",
"url": "https://api.ipify.org?format=json",
})
if r.status_code == 402 and r.json().get("code") == "quota_exhausted":
raise SystemExit("Member hit the 100 MB ceiling β stop, do not retry.")
print(r.json()["bytes"], "bytes metered Β·", r.json()["quota"]["leftMB"], "MB left")
A member who joins today gets exactly 100 MB of total transfer β that number is a wall, not a warning. It is charged by every metered action and enforced before any traffic leaves the gateway.
| What the member does | Metered as | When it is refused |
|---|---|---|
| Extract proxy lines | 10 MB per line | 11th line without a top-up (403 HARD LIMIT) |
| Forward an API call | request + response bytes, 1 KB minimum | any call after the ceiling (402 quota_exhausted) |
| A mid-flight download that would overshoot | cut off at the last allowed byte | truncated: true |
| Buy extra traffic | β | blocked on free plans (403 BLOCKED) until the owner upgrades |
Owner-only escape hatch (Admin Panel β Users β "Set cap" / "Lift 100MB"):
POST /api/admin/set-quota { "userId": "u_xxx", "limitMB": 5000 } β widen the ceiling
POST /api/admin/set-quota { "userId": "u_xxx", "lift": true } β remove it (paid / staff accounts)
GET /api/plan β { "quota": { "limitMB": 5000, "usedMB": 100, "leftMB": 4900 } }
β Enforcement lives in the code that answers /api/*. Serve the dashboard from a static host and the ceiling is metered in the browser (demo mode) β convenient, but a member with devtools can edit their own localStorage. Run node server.js (same rule engine, one shared JSON DB, HttpOnly session cookie) and the limit becomes impossible to talk past.
Host / server: the host on YOUR line, e.g. rp.evomi.com Port: 1002 for SOCKS5, 1000 for HTTP β exactly as printed on the line Username: the whole user string on the line, e.g. pnparves116 Password: the whole password, _country-β¦_session-β¦_lifetime-β¦ included IP change URL: none needed β a new extraction is a new IP, and a used line expires by itself
Use π± App setup on any result row to copy those four values one at a time. In your app the type must be SOCKS5 (or HTTP, if you asked for HTTP) and authentication must be username + password β leaving it on None is the single most common reason a perfectly good line looks broken. Only the host belongs in the Server box; the whole host:port:user:pass string belongs only in tools that accept a full line.
Every part above comes from the line you extracted β there is no shared host:port to look up, and none is written into this page. The board prints a live/unreachable stamp for the endpoint, and no line is issued while nothing can be reached.
Only https://owlproxy.pro is the shop. The owlproxy.pro copy is a static demo: it has no PHP behind it, so it cannot mint a line for anyone β landing there now sends you straight back to the live shop. Two things then make a working line look broken: (1) the line was taken from the demo, or is older than its lifetime, or (2) the app is set to the wrong type or to Authentication: None. Press β‘ Test on the server (or β‘ Test this line) on the board: it dials the proxy from the server and prints the exit IP it came out with. That verdict is the ground truth β if it says β works and your app still fails, the fix is in the app, not in the line.
That sentence comes from the app, and it only ever means one of four things, all of them about which box the text went into — never about the line being fake:
Under every line, π± app setup now has a π Paste check: paste into its three boxes exactly what your app is holding, and it names the box that is wrong and hands you the right value. It reads nothing from your device and sends nothing anywhere — it only compares text against the line above it. If the card says ✓ all three boxes match and the app still refuses, press β‘ Test on the server: when that shows a green exit IP too, the problem is the app’s protocol (it must be SOCKS5, with authentication set to username + password, never None).
The card opens by itself the moment a line is issued β six boxes in the order your app asks for them (Protocol Β· Server Β· Port Β· Authentication method Β· Username Β· Password), each value in its own read-only field with its own copy button, so nothing has to be selected by hand. If your app has a scanner (the small square icon on its profile screen), press π· QR Code instead: it carries socks5://user:pass@host:port for that line, and the profile fills itself in. A line dies 30 minutes after it is minted, so a scan or a copy should be followed by Start right away.
The country box takes any ISO‑3166 two-letter short name β all 250 of them, not a hand-picked list: BD, DE, MG, TG, ZW. Typing the name instead works too β Bangladesh, United States, even TΓΌrkiye with its accents or a city like Dubai β because the shop resolves names to codes before asking the provider. That matters: a full name used to be chopped into letter pairs and shipped as junk, which is exactly what made a chosen location look ignored. Something that is no country at all is now named back to you instead of being quietly dropped, and every line is labelled with the country that is actually inside its credential β what the row, the app-setup card and the export show is the answer that came back, never the option that happened to be highlighted on screen. Several codes at once are allowed (DE,TG); the provider picks among them and the line tells you which one it picked.
On your own gateway (the little program in the gateway zip) the country lives in the Username, the way every commercial gateway does it: np_a1b2c3_zone_MG_sid_71132125_time_30. The two letters after zone_ are an ISO short name, and you may edit them yourself in the app β change zone_MG to zone_JP, press Start, and the next connection leaves from Japan. No re-extract, no new line, nothing charged twice: the gateway reads those two letters, asks the shop which credential exits from that country, chains through it, and reuses that answer for the rest of the line’s life. The Password is your gateway pin β seven digits, the same shape the big shops hand out. A zone nobody routed is refused with a message that says what to configure, rather than quietly sending you out of some other country.
API β you paste your provider account's key and save; that is the whole setup. There is no second switch to flip: the account is live the moment the key is accepted, and the GB that account holds is what your members can be issued. When it runs dry, extraction stops and nobody is charged for a line that does not exist. The same panel holds one more field: the server name printed on every line. Put your own hostname there (an A or CNAME record pointing at the gateway members dial) and no line leaves this shop with a reseller's host in it β a name that cannot be reached is never printed, because a dead host on a line is a refund.
Free proxy β whatever number of MB you confirm in that box is exactly what a new account receives when it claims the free trial, and the same number is the wall on that account: extraction, forwarding and the API all count against it. It is deducted from your own pool. Accounts that already claimed keep the ceiling they were given; your new number applies to the ones after it.
Promo code β a code, the GB it gives, and how many people may redeem it. Only the first that many accounts can claim it, each one once: the tenth account is refused even if the code is still printed everywhere. Under the box you see the claim list itself β address, GB, timestamp, in the order they claimed β so “only the first 50” is something you can show, not something you have to trust. Members redeem the code in Referral, under their referral link; a correct code lands straight in their balance and their ceiling rises by exactly that much so the GB is actually spendable.
When a line is extracted, the gateway mints a fresh random password for that one line β 12 characters, no look-alike letters β and ties it to that line's country and expiry. Copying a line to a friend and changing two letters in the Username still fails: the password belongs to the line, not to the account. Your standing key keeps working for the API and for apps that need one credential for everything, so nothing you already run breaks; but what you hand out is a line, and a line now carries its own secret.
Two layouts exist and mixing them up is the most common reason an app answers “the provided credentials are invalid” on a perfectly good line:
The app-setup card knows which of the two it is showing and labels each row accordingly (“the SHORT half” / “the LONG half” / “your gateway pin”), and π Paste check compares what you typed with the line itself: a swapped pair gets a one-tap β swap the two boxes button, a truncated password says how many characters the app kept, and a whole line pasted into Server is split for you.
The shop does not invent addresses. Every line it hands out is minted at the moment of the request from the upstream account saved in Admin βΈ Upstream provider (Evomi's public API: https://api.evomi.com/public/generate), so what a member copies is current, and the same account's balance β read live, shown in that card β is what the shop meters. Product, protocol, session type, line lifetime in minutes (your provider's own ceiling is 1440) and the maximum lines per extraction are all set in that card; turning it off sends issuance back to the gateway below, and no setting here can make a fake line appear.
The key is never printed anywhere. It lives in a private secrets file outside the web folder β a place no browser can reach β and the board only ever reads back β’β’β’β’last4. If that key was ever pasted into a chat, a mail or a screenshot, rotate it at my.evomi.com/settings/api and save the new one in the same card; the shop picks it up on the next request.
If the provider refuses β no balance, a dead key, a network fault β the extraction ends with 502 / 503, the reason in plain words, and charged: false: a member never loses a megabyte for a line that was never minted. If it mints fewer lines than were asked for, only the lines that exist are charged. Lines the owner pastes in Admin βΈ Imported lines are treated the same way: labelled pending until a server check proves them, and never shown as verified without one.
A proxy line is only as real as the machine answering host:port. The shop ships that machine's program: a dependency-free Node gateway that authenticates every connection against the shop and reports the bytes it carried, so a member's 100 MB is spent on traffic that actually flowed. Until it is running, the board refuses to issue lines (and refuses to charge for them) rather than hand out an address nobody can dial.
After the first line is issued the board tests it for you: every row has a β‘ Test this line button (and the console header a β‘ Test every line one). The check runs on the server, never in the browser, and walks three stages β the name must resolve, the port must accept a TCP connection, and an authenticated fetch must come back through the proxy. Each row then carries the verdict and the reason (β works Β· exit IP Β· 214ms or β tcp β connection refused). A test costs no traffic: nothing is charged for asking.
# 1. a box with a public IP (a β¬4 VPS is enough) β point DNS at it
DNS: A record pool.yourdomain.com β 203.0.113.10 (only if you run your own gateway)
# 2. install and run the shipped gateway
scp gateway/gw-server.js user@vps:~/ && ssh user@vps
GW_ORIGIN=https://owlproxy.pro GW_PORT=7777 GW_TOKEN=\
<copied from Admin βΈ Gateway βΈ Rotate gateway token> node gw-server.js
# 3. keep it up (systemd)
[Unit]
Description=OwllProxy gateway
After=network-online.target
[Service]
WorkingDirectory=/home/user
Environment=GW_ORIGIN=https://owlproxy.pro
Environment=GW_PORT=7777
Environment=GW_TOKEN=put-the-real-token-here
ExecStart=/usr/bin/node /home/user/gw-server.js
Restart=always
User=user
[Install]
WantedBy=multi-user.target
# 4. optional: sell real residential exits instead of your own IP β the per-line
# session id is carried into the provider username, so sticky/rotating still works
Environment=GW_UPSTREAM=gw.provider.com:2333:your-zone-login:password
What the gateway does with each connection: POST /api/gw/auth (username + password + shared token β allow / deny, and the member's remaining MB), then POST /api/gw/usage with the byte count every two seconds. A member who runs out is dropped mid-session; a wrong password never gets a tunnel; anonymous traffic is answered with 407 and nothing is relayed. Both endpoints are in api.php, so the same gateway works against the PHP host and against node server.js.
import requests
proxies = {
'http': 'socks5://:@:1002',
'https': 'socks5://:@:1002'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print("Connected Exit IP:", response.json()['ip'])
const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');
const agent = new SocksProxyAgent('socks5://:@:1002');
const res = await axios.get('https://api.ipify.org?format=json', { httpsAgent: agent });
console.log('Exit IP:', res.data.ip);
curl -x socks5://<user>:<pass>@<host-from-your-line>:1002 https://api.ipify.org
| Route / Endpoint | Guest | Member | Admin | Notes |
|---|
| π Admin / Owner | the owner panel answers to one reserved address only β the owner's own Gmail. Any other email, however it is typed in, stays a member account. No password is ever printed on this page. |
| π€ Demo Member | demo@owlproxy.pro / demo123 |
| β‘ Instant Trial | 1-Click instant temporary account (100MB free trial) |