API reference
The public JSON API powers self-serve signup, account management, and payments. Your whisker key in the path is the management credential. No separate API key.
Base URL: your site's public origin (e.g. https://socks.cat).
Signup challenge
GET /signup/challenge
Response 200 { "nonce": "..." } — a one-time nonce to echo back to
POST /signup (abuse gate).
Create an account
POST /signup
Body { "nonce": "<from /signup/challenge>" }
Response 200
{
"whisker": "whisker-DLDI-ZF6C-...",
"username": "cat-XS73LMPQOFK762Q4",
"password": "a14c2f9f5068d0ddd2f50c39bad4bfdd",
"life": 1
}
whisker is the management secret (shown once).
username is the collar tag (proxy username base). password is the life-1
full pawprint. Never send the whisker to the proxy — only collar + pawprint.
Look up an account
GET /account/{whisker}
Response 200
{
"id": 42,
"username": "cat-XS73LMPQOFK762Q4",
"password": null,
"life": 1,
"bytes_in": 52428800,
"bytes_out": 104857600,
"traffic_remaining_gib": 12.4,
"traffic_purchased_gib": 50.0,
"traffic_used_gib": 37.6,
"default_selection": "country-us-isp-comcast",
"allowed_ips": ["10.0.0.0/24", "203.0.113.7/32"]
}
password is always null — derive pawprints in settings or via the derive endpoint.
404 if no account matches the whisker.
Derive a pawprint
GET /account/{whisker}/derive
GET /account/{whisker}/derive?selection=country-us-state-ut-type-residential
GET /account/{whisker}/derive?type=residential&isp=comcast
Optional query parameters narrow a scoped pawprint:
| Param | Meaning |
|---|---|
selection | keyed builder route (preferred), e.g. country-us-isp-comcast |
type | residential, mobile, or datacenter |
isp | ISP catalog code (lowercase) |
territory | internal geo code — prefer selection or the web UI |
Omit all params for a full pawprint (any route).
Response 200
{
"username": "cat-XS73LMPQOFK762Q4",
"life": 1,
"scope": "<internal>",
"pawprint": "0a6b52bfad0cab7a8fa5b56e213ff032"
}
scope is internal — you do not put it in proxy clients. Requires a whisker
credential (400 if you pass a collar tag).
Rotate pawprints
POST /account/{whisker}/rotate
Bumps life; old pawprints stop working after the grace window. Returns a new full pawprint for the new life.
Response 200 { "username": "...", "life": 2, "password": "..." }
(password here is the new full pawprint.)
Reissue whisker
POST /account/{whisker}/reissue
Mints a new whisker key and invalidates the old one immediately.
Response 200
{
"whisker": "whisker-NEW-...",
"username": "cat-XS73LMPQOFK762Q4",
"password": "...",
"life": 1
}
Set the default route
POST /account/{whisker}/default
Body { "selection": "country-us-isp-comcast" } — routing tag
string; empty clears it. Response 200 { "default_selection": "..." },
404 if not found.
Add an allowed IP
POST /account/{whisker}/ips
Body { "cidr": "10.0.0.0/24" } — a bare IP (stored as a host route) or CIDR.
Response 200 { "added": "..." }, 400 on an unparseable address, 404
if not found.
Remove an allowed IP
POST /account/{whisker}/ips/remove
Body { "cidr": "10.0.0.0/24" }. Response 200 { "removed": "..." }.
Request a payment quote
POST /quote
Body { "token": "<whisker>", "coin": "monero", "gib": 5.0 }
Response 200
{
"coin": "monero",
"address": "8B...",
"amount": 0.004,
"amount_atomic": 4000000000,
"expires_at": 1712345678
}
Quote status
GET /quote-status?address=...&coin=monero
Response 200
{
"credited": false,
"confirmations": 3,
"required": 10,
"seen": true
}
Locations & pricing
GET /locations → array of exits with country/city/isp/type tags
GET /catalog/locations → structured catalog for the web builder
GET /pricing → { "price_usd_per_gb": 1.5, "min_topup_usd": 5.0, "coins": [...] }
Status codes
| Code | Meaning |
|---|---|
200 | OK |
201 | Created |
204 | No content (delete) |
400 | Validation error |
404 | Not found |
409 | Conflict |
429 | Rate limited (signup or credential operations) |
500 | Server error |