Customer Integration API

Detailed docs for each API: auth, parameters, body schema, and working request/response examples.

Quick Start

1. Put your key in header: x-api-key: pk_xxx
2. Test auth first:
curl -X GET "http://YOUR_HOST:3000/api/key/me" \
  -H "x-api-key: pk_xxxxxxxxxxxxxxxxx"
3. Then call any customer endpoint below.

Navigation

Authentication + Profile

GET /api/key/me Auth: x-api-key
Purpose: validate key and return permissions, quotas, and owned resources.
curl -X GET "http://YOUR_HOST:3000/api/key/me" \
  -H "x-api-key: pk_xxxxxxxxx"
{
  "name": "customer-a",
  "permissions": ["check_proxy", "vpn_clients"],
  "my_gateways": ["gw_customer_a"],
  "proxy_checks_used": 12,
  "proxy_check_limit": 500
}

Proxy Checker

POST /api/check Auth: optional x-api-key
Body:
{
  "proxies": ["socks5://1.2.3.4:1080", "host:port:user:pass"],
  "concurrency": 5,
  "timeout": 30000
}
cURL:
curl -X POST "http://YOUR_HOST:3000/api/check" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_xxxxxxxxx" \
  -d '{"proxies":["socks5://1.2.3.4:1080"],"concurrency":5,"timeout":30000}'
Response:
{ "jobId": "8f0...", "total": 1 }
GET /api/stream/:jobId SSE
Subscribe to realtime results from /api/check job.
const es = new EventSource(`/api/stream/${jobId}`);
es.onmessage = (e) => console.log(JSON.parse(e.data));

My Gateways (CRUD + Control)

GET /api/customer/proxies Auth: x-api-key
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/proxies"
POST /api/customer/proxy
Body:
{
  "proxy_url": "socks5://user:pass@host:port",
  "allow_http_proxy": true
}
curl -X POST "http://YOUR_HOST:3000/api/customer/proxy" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"proxy_url":"socks5://user:pass@host:port","allow_http_proxy":true}'
PUT /api/customer/proxy/:name
Update existing gateway's upstream proxy.
curl -X PUT "http://YOUR_HOST:3000/api/customer/proxy/gw_a" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"proxy_url":"socks5://new_user:new_pass@host:port"}'
DELETE /api/customer/proxy/:name
curl -X DELETE "http://YOUR_HOST:3000/api/customer/proxy/gw_a" \
  -H "x-api-key: pk_xxx"
GET /api/customer/gateway/:name/ip
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/gateway/gw_a/ip"
{ "ip": "104.21.x.x", "changed": false }
POST /api/customer/gateway/:name/:action(start|stop|restart)
curl -X POST "http://YOUR_HOST:3000/api/customer/gateway/gw_a/restart" \
  -H "x-api-key: pk_xxx"
POST /api/customer/gateway/:name/mitm/:action(start|stop)
curl -X POST "http://YOUR_HOST:3000/api/customer/gateway/gw_a/mitm/start" \
  -H "x-api-key: pk_xxx"

OpenVPN Client APIs

GET /api/customer/gateway/:name/clients
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/gateway/gw_a/clients"
POST /api/customer/gateway/:name/client
Creates OpenVPN profile and returns ovpn text.
curl -X POST "http://YOUR_HOST:3000/api/customer/gateway/gw_a/client" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"client_name":"laptop1"}'
{
  "ok": true,
  "name": "laptop1",
  "cert_name": "gw_a_ab12cd34_laptop1",
  "ovpn": "client\n..."
}
GET /api/customer/vpn/client/:certName/ovpn
curl -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/vpn/client/gw_a_ab12cd34_laptop1/ovpn"
DELETE /api/customer/vpn/client/:certName
curl -X DELETE -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/vpn/client/gw_a_ab12cd34_laptop1"

WireGuard Client APIs

GET /api/customer/gateway/:name/wg-clients
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/gateway/gw_a/wg-clients"
POST /api/customer/gateway/:name/wg-client
curl -X POST "http://YOUR_HOST:3000/api/customer/gateway/gw_a/wg-client" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"client_name":"phone1"}'
{
  "ok": true,
  "name": "phone1",
  "wg_name": "gw_a_ab12cd34_phone1",
  "conf": "[Interface]\n...",
  "qr": "data:image/png;base64,..."
}
GET /api/customer/wg/client/:wgName
curl -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/wg/client/gw_a_ab12cd34_phone1"
DELETE /api/customer/wg/client/:wgName
curl -X DELETE -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/wg/client/gw_a_ab12cd34_phone1"

L2TP APIs

GET /api/customer/l2tp
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/l2tp"
POST /api/customer/l2tp/gateway/:name
Create (or return existing) L2TP credentials for your owned gateway.
curl -X POST -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/l2tp/gateway/gw_a"

Proxy Library APIs

GET/api/customer/library
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/library"
DELETE/api/customer/library/:proxy
curl -X DELETE -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/customer/library/socks5%3A%2F%2F1.2.3.4%3A1080"
DELETE/api/customer/library
curl -X DELETE -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/library"
GET/api/customer/library/export
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/customer/library/export" -o proxy-library.txt

Public Gateway APIs (Scoped Access)

These endpoints require gateway access via x-api-key or admin x-vpn-token.
GET/api/public/g/:name/info
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/info"
POST/api/public/g/:name/mitm/:action(start|stop)
curl -X POST -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/mitm/start"
POST/api/public/g/:name/client
curl -X POST "http://YOUR_HOST:3000/api/public/g/gw_a/client" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"client_name":"guest1"}' -o gw_a_guest1.ovpn

Capture APIs

GET/api/public/g/:name/captures
Query params: limit, q, method, host_like, path_like, status_min, status_max, before_ts, after_ts
curl -H "x-api-key: pk_xxx" \
  "http://YOUR_HOST:3000/api/public/g/gw_a/captures?limit=100&status_min=400&q=login"
{ "flows": [{"id":"...","method":"GET","status":200}], "count": 100, "total": 4321 }
GET/api/public/g/:name/captures/:id
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/captures/flow123"
DELETE/api/public/g/:name/captures
curl -X DELETE -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/captures"
GET/api/public/g/:name/stats
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/stats"
GET/api/public/g/:name/export.ndjson | .har | .csv
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/export.ndjson" -o gw_a.ndjson
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/export.har" -o gw_a.har
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/export.csv" -o gw_a.csv

Analyze APIs

GET/api/public/g/:name/analyze/info
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/analyze/info"
POST/api/public/g/:name/analyze/models
curl -X POST "http://YOUR_HOST:3000/api/public/g/gw_a/analyze/models" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"provider":"openai","apiKey":"sk-..."}'
GET/api/public/g/:name/analyze
curl -H "x-api-key: pk_xxx" "http://YOUR_HOST:3000/api/public/g/gw_a/analyze?limit=3000&since_minutes=60"
POST/api/public/g/:name/analyze/ai
curl -X POST "http://YOUR_HOST:3000/api/public/g/gw_a/analyze/ai" \
  -H "x-api-key: pk_xxx" -H "Content-Type: application/json" \
  -d '{"provider":"openai","apiKey":"sk-...","model":"gpt-4o-mini","limit":3000}'
POST/api/public/g/:name/analyze/ai/streamSSE
const r = await fetch('/api/public/g/gw_a/analyze/ai/stream', {
  method: 'POST',
  headers: { 'x-api-key': key, 'Content-Type': 'application/json' },
  body: JSON.stringify({ provider: 'openai', apiKey: 'sk-...', model: 'gpt-4o-mini' })
});
const reader = r.body.getReader();

SSE / WebSocket

Gateway realtime events:
const ws = new WebSocket(`wss://YOUR_HOST/ws/g/gw_a?api_key=${encodeURIComponent(key)}`);
ws.onmessage = (e) => console.log(JSON.parse(e.data));
Gateway logs stream (SSE):
const es = new EventSource(`/api/public/g/gw_a/logs/stream?api_key=${encodeURIComponent(key)}&service=all&lines=100`);
es.onmessage = (e) => console.log(JSON.parse(e.data));

Error Handling

401 Invalid key/token
403 No permission / no gateway access
404 Resource not found
429 Proxy-check quota exceeded
500 Server-side error
{ "error": "message" }

Machine-Readable Contract

Import into Postman/Insomnia/Bruno/codegen: