Overview
Last 7 days
DAILYBy service (30d)
By country (30d)
| Country | GB | Flows |
|---|
Usage
Daily breakdown
| Day | Country | Service | GB | Flows |
|---|
Tunnel credentials
Generate credential
Generate returns the credential currently active on your account (same password every time — safe to call after a reload). Rotate revokes the existing password and mints a new one. Use it the moment you suspect the password has leaked. Anything currently connected with the old password will be dropped within 30 seconds.
Billing
Top up
Payments
| Date | Provider | Purpose | Amount | Credit | Status |
|---|
Developer docs
1 · Endpoints
Two proxy frontends, both authenticated with the same SOCKS5-style username + password from the Tunnel credentials tab.
| Protocol | Endpoint | Notes |
|---|---|---|
| SOCKS5 | gateway.vela.watch:1080 | TCP + UDP ASSOCIATE |
2 · Username format
The username embeds your account ID, a sticky session ID, the country you want to egress through, and (optionally) the streaming service. Same session = same residential exit IP. The binding lasts until you explicitly rotate or discard it — there is no fixed expiry while traffic keeps flowing (see § 6 for the exact lifetime rules).
vela-{customer_id}-session-{session_id}-country-{cc}[-service-{svc}]
# Examples
vela-u_abc123-session-s_0001-country-uk
vela-u_abc123-session-s_0001-country-uk-service-bbc
vela-u_abc123-session-s_0001-country-it-service-netflix
3 · curl / Firefox / bots
Drop-in usage. Replace USER / PASS with the values from the Tunnel credentials tab.
# curl via SOCKS5
curl --proxy "socks5h://USER:PASS@gateway.vela.watch:1080" https://www.bbc.co.uk/iplayer
# Python (requests)
import requests
proxies = { "https": "socks5h://USER:PASS@gateway.vela.watch:1080" }
r = requests.get("https://www.bbc.co.uk/iplayer", proxies=proxies, timeout=30)
# Firefox / Chrome → Network settings → Manual proxy → SOCKS v5
# Host: gateway.vela.watch Port: 1080 Auth: USER / PASS
4 · Streaming allowlist
Only branded streaming hostnames pass the gateway policy. Everything else is rejected (and not billed). Request additions from support.
| Service | Country | Service tag |
|---|---|---|
| Netflix UK | UK | netflix |
| Prime Video UK | UK | prime |
| BBC iPlayer | UK | bbc |
| ITVX | UK | itvx |
| Channel 4 | UK | c4 |
| Sky / NOW | UK | sky |
| Disney+ UK | UK | disney |
| Paramount+ | UK | paramount |
| Apple TV+ | UK | appletv |
| DAZN UK | UK | dazn |
5 · Account API
REST API at the same origin as this dashboard. All endpoints are authenticated with your JWT or HTTP Basic + API key.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/b2b/me | Account + wallet snapshot |
| GET | /v1/b2b/usage | Daily metered usage |
| GET | /v1/b2b/usage/timeseries | Hourly time series for charts |
| GET | /v1/b2b/usage/by-country | 30-day usage by country |
| GET | /v1/b2b/usage/by-service | 30-day usage by streaming service |
| GET | /v1/b2b/sessions | Live + recent sticky sessions |
| GET | /v1/b2b/proxy/assigned | Your currently-bound residential exits (see § 6 / 8) |
| POST | /v1/b2b/proxy/rotate | Free the sticky binding so the next request lands on a fresh node |
| POST | /v1/b2b/proxy/discard | Same as rotate plus blacklist the previous node for your account |
| POST | /v1/b2b/proxy/blacklist/clear | Wipe your discard list |
| GET | /v1/b2b/api-keys | List your active API keys |
| POST | /v1/b2b/api-keys | Mint a new API key |
| DELETE | /v1/b2b/api-keys/{id} | Revoke an API key |
| POST | /v1/b2b/payments/checkout | Start a top-up |
| GET | /v1/b2b/tunnel-credential | Cached SOCKS5 secret (idempotent) |
| GET | /v1/b2b/tunnel-credential?rotate=1 | Force a fresh secret (use after a leak) |
6 · Sticky session behaviour — what actually pins you to an IP
The session token in the SOCKS5 username is a stable opaque string you control. Pick one per logical "user" or "scrape job" and reuse it for as long as you want the same exit IP. The gateway pins (customer, session, country, service) → one residential node and keeps that binding alive under the following rules:
| Event | Binding survives? | Detail |
|---|---|---|
| Your SOCKS5 client opens and closes TCP connections normally | Yes | SOCKS5 is per-request — every new request re-authenticates with the same username, hits the same sticky key, same node. |
You keep using the same session for hours / days | Yes | Every flow refreshes the binding's idle timer (rolling window). |
| You go idle (no traffic at all) | Yes up to 7 days idle | Hard ceiling: the binding key has a 7-day idle TTL so abandoned sessions eventually free their slot. Configurable via STICKY_TTL_SECONDS at the gateway. Active traffic resets this — it only matters when you stop sending requests. |
You call POST /v1/b2b/proxy/rotate | No — by your request | Binding deleted. Next request picks a fresh node from the country pool. Previous node remains available to come back on a future re-roll. |
You call POST /v1/b2b/proxy/discard | No — by your request | Binding deleted and the previous node is blacklisted for your account. Use after detecting a bad IP (banned by destination, slow, etc.). |
| The residential node goes unhealthy or is removed | No — by us | Binding cleared automatically, next request re-picks. Should be rare. |
What this means in practice: there is no hidden 30-minute or 1-hour expiry. The gateway will keep sending you out the same residential IP indefinitely as long as you keep using the same session and the upstream stays healthy. The only ways the IP changes are: (1) you call rotate/discard, (2) the node disappears server-side, or (3) you stop sending traffic for more than 7 days. Rotating IPs has a cost — destinations see a new TLS + cookie handshake and many treat that as a re-login, so don't rotate inside an active video stream.
7 · IP selection & rotation — how it works step by step
Each request you send through the gateway is mapped to one residential exit IP by the following deterministic pipeline. Understanding this is the difference between a working scraper and a banned account.
┌─ STEP 1 ─ Username parse ──────────────────────────────────────┐
│ The gateway splits your username on the wire: │
│ vela-{customer}-session-{session}-country-{cc}-service-{svc} │
│ ↑ ↑ ↑ ↑ │
│ identity stickiness key pool filter optional filter │
└────────────────────────────────────────────────────────────────┘
┌─ STEP 2 ─ Sticky lookup (Redis) ───────────────────────────────┐
│ Key: sticky:{customer}:{session}:{country}:{service} │
│ If hit → reuse the SAME upstream IP from last time. │
│ Idle TTL refreshes on every flow (rolling, default 7 days). │
│ Active traffic = effectively no expiry. │
└────────────────────────────────────────────────────────────────┘
┌─ STEP 3 ─ Pool selection (cache miss only) ────────────────────┐
│ Filter the residential pool down to nodes where: │
│ node.country == requested country, AND │
│ node.healthy == true, AND │
│ (no -service- given OR node.capabilities contains it) │
│ Hash-pick deterministically: hash(customer+session) % len(pool)│
│ → Same session always lands on the same node while it exists. │
└────────────────────────────────────────────────────────────────┘
┌─ STEP 4 ─ Persist + dial ──────────────────────────────────────┐
│ Write the choice back to Redis with sticky TTL. │
│ Dial the destination through that node (SOCKS5 or HTTP CONNECT)│
│ Tunnel the bytes, meter both directions, decrement wallet. │
└────────────────────────────────────────────────────────────────┘
Choosing the right pattern
| Goal | What to do | Effect |
|---|---|---|
| Persist one identity (Netflix login, DRM session) | Keep session constant across all requests | Same exit IP for the whole job. DRM stays happy. |
| Rotate IP every request (defeat rate-limits) | Randomise session per request (UUID v4) | Each call hits a different residential node from the country pool. |
| Parallel scrapers, independent IPs | One session per worker, kept stable inside it | N workers → up to N distinct exits, each one sticky. |
| Force a fresh IP mid-job | Call POST /v1/b2b/proxy/rotate (keeps session stable) OR change the session suffix once | Both clear the binding and trigger a new pool pick. The old node is not blacklisted unless you call /discard. |
| Country switch | Change country | Different country pool. Different exit IP, different geo. |
Important: rotating IPs has a cost. A new sticky session triggers a fresh TLS + cookie handshake at the destination, and many streaming services interpret it as a suspicious re-login. Don't rotate inside a video stream — only between scrape jobs.
8 · Session control — rotate, discard, list assigned IPs
Three endpoints let you take direct control of which residential exit your session lands on. Pool-wide listing is never exposed — you only ever see the IPs you've actually been routed through.
| Method | Path | Effect |
|---|---|---|
| GET | /v1/b2b/proxy/assigned | Lists your currently-bound sticky exits (session, country, exit IP, node_ref). Blacklist size only — never the IDs. |
| POST | /v1/b2b/proxy/rotate | Body {session, country, service?}. Frees the binding, next request picks a fresh node from the country pool. Previous node can come back. |
| POST | /v1/b2b/proxy/discard | Body {session, country, service?}. Same as rotate plus blacklists the previous node so it never comes back for your account. Max 64 entries, 30-day TTL. |
| POST | /v1/b2b/proxy/blacklist/clear | Wipes your discard list. Use when the pool has shrunk past usefulness. |
What you see vs what stays hidden
| Field | Exposed? | Why |
|---|---|---|
exit_ip | ✓ for your own bindings | Your destination saw it already. No new info leaked. |
node_ref | ✓ opaque hash | Stable per-customer so you recognise "same exit, different session". HMAC of (your customer id, internal node id) — useless to anyone else. |
| Internal node id | ✗ | Pool identifiers stay private. |
| Unused pool members | ✗ | You only see what you've been routed through. The catalogue stays hidden. |
| Discarded node ids | ✗ — count only | Cardinality lets the UI render a badge without listing the contents. |
# list current assignments
curl -H "Authorization: Bearer $JWT" https://vela.watch/v1/b2b/proxy/assigned
# rotate (same session keeps working, lands on a new IP)
curl -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{"session":"scrape-001","country":"UK"}' \
https://vela.watch/v1/b2b/proxy/rotate
# discard the bad IP, blacklist it for this account
curl -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{"session":"scrape-001","country":"UK"}' \
https://vela.watch/v1/b2b/proxy/discard
Lifetime, exactly: the binding has no fixed expiry. It survives every TCP connect/disconnect cycle of your SOCKS5 client and every minute of active traffic. The only timer is a 7-day idle TTL — i.e. if you send no traffic at all for 7 consecutive days the binding rolls off. Active traffic resets that timer on every flow. So in practice: you keep the same IP until you call /rotate, /discard, or stop using the session entirely. Override the default 7-day idle ceiling at the deployment level with STICKY_TTL_SECONDS.
9 · SOCKS5 ATYP — --socks5 vs --socks5-hostname
Our policy filter inspects the destination hostname, not the post-DNS IP. SOCKS5 supports two address types: ATYP=1 (IPv4) and ATYP=3 (domain). Pick the right one or every request gets denied even with valid credentials.
| Client setting | What the gateway sees | Result |
|---|---|---|
curl --socks5 USER:PASS@host:1080 | ATYP=1 IPv4 (client did local DNS) | Denied — gateway can't match an IP to the streaming allowlist. |
curl --socks5-hostname USER:PASS@host:1080 | ATYP=3 domain string | Allowed if the host suffix matches the allowlist. |
socks5h:// URL scheme (Python requests, Go) | ATYP=3 domain string | Allowed — same as --socks5-hostname. |
socks5:// URL scheme | Implementation-dependent (usually ATYP=1) | Likely denied. Use socks5h:// instead. |
Why we enforce ATYP=3: a hostname is the only thing we can match against the streaming allowlist without trusting the client's DNS. If we accepted ATYP=1 we'd have to do a reverse-DNS or re-resolution — both lossy, both spoofable. Sending the hostname through the proxy also means DNS itself egresses through the upstream node, not your machine — important if you don't want your home ISP seeing every streaming query.
# Correct curl --socks5-hostname USER:PASS@gateway.vela.watch:1080 https://www.netflix.com/ curl --proxy socks5h://USER:PASS@gateway.vela.watch:1080 https://www.bbc.co.uk/iplayer # Wrong — denied curl --socks5 USER:PASS@gateway.vela.watch:1080 https://www.netflix.com/ curl --proxy socks5://USER:PASS@gateway.vela.watch:1080 https://www.bbc.co.uk/iplayer