Create - POST /v1/sessions
Creates a session and returns a fully-formed WireGuard config. Hand it to any WireGuard library, or write it to a file and wg-quick up.
Example
Response
Body
| Field | Type | Required | Notes |
|---|---|---|---|
region | string | yes | One of the codes from GET /v1/regions. |
client_public_key | string | no | Base64 WireGuard public key (32 bytes). When supplied, the server uses it directly and the returned wg_config omits PrivateKey (the caller already has it locally). When omitted, the server generates a keypair and returns both halves embedded in wg_config. |
Response
| Field | Type | Notes |
|---|---|---|
id | string | Opaque session id. Use for status lookups. Surfaces in invoices on the paid tier. |
public_ip | string | The exit IP your traffic will appear from. |
wg_config | string | Full WireGuard config. If you supplied client_public_key, no private key is included; otherwise treat the string as a secret. |
expires_at | string (RFC 3339) | Server-side hard cutoff (tier max-session cap). |
tier | string | Resolved account tier: anonymous, free, or paid. |
Errors
| Status | Body | Why |
|---|---|---|
| 400 | invalid json / <reason> | Malformed body or invalid client_public_key. |
| 401 | missing token / invalid token | Bearer header missing or token expired/revoked. |
| 402 | quota exceeded (JSON body with tier + usage breakdown + reset times) | Per-tier window cap hit. Body includes tier, bytes_used, bytes_limit, session_seconds, session_limit, bytes_window_resets_at, seconds_window_resets_at, resets_at (whichever of the two tripped, for single-field consumers), hint. |
| 503 | no active nodes / no active node in region <code> | Region has no healthy nodes. The latter response also includes available: [...] so the client can suggest another region. |
| 503 | subnet exhausted | Region is technically up but all client IPs in its /24 are taken. Retry shortly. |
| 503 | peer apply failed; node may be disconnected | The exit node didn’t accept the session within the timeout. Retry; the server will route around a persistently unreachable node within a minute. |
Status - GET /v1/sessions/{id}
Look up the live state of a session. The CLI polls this every 10 seconds while a tunnel is up; the response shape feeds the live status line.
Example
Response
Response
21000 millicents = 21 cents = €0.210 for ~21 min of session time, plus a fraction of a cent for the bytes.)
On a terminated session:
Response
Response
| Field | Type | Notes |
|---|---|---|
id | string | Echo of the path id. |
terminated_at | string (RFC 3339), optional | Set once the server has ended the session (Ctrl-C teardown also lands here). Empty / absent means the tunnel is still live. |
terminated_reason | string, optional | One of: quota_exceeded, expired (30-day safety ceiling hit), idle (>5 min without WG handshake), or other reason text the server attaches at terminate. |
bytes_in / bytes_out | integer | Cumulative bytes through the tunnel since created_at. Updated by node-agent heartbeats every ~10-30 seconds. |
created_at | string (RFC 3339) | Session start. Use for client-side elapsed-time math; do not depend on server-client clock alignment. |
tier | string | Account tier the session was created under. |
cost_time_millicents | integer, optional | Time-leg cost so far in millicents (1/1000 of a cent, i.e. 1/100,000 of cost_currency). Sub-cent precision keeps short sessions from rounding to zero. Paid tier only; omitted when tier != paid or when the server can’t yet confirm rates (rare). |
cost_bytes_millicents | integer, optional | Byte-leg cost so far in millicents, same units as cost_time_millicents. Total cost = cost_time_millicents + cost_bytes_millicents. |
cost_currency | string, optional | ISO 4217 lowercase code (eur, …). All v1 pricing is in EUR; the field is present so future regional pricing has somewhere to land. Omitted under the same conditions as the cost fields. |
quota_bytes_used | integer | Bytes used in the current bytes window (rolling 7 days on anonymous and free). |
quota_bytes_limit | integer | Per-tier byte cap for the current window. 0 for paid (unmetered). |
quota_seconds_used | integer | Cumulative session seconds in the current time window (24 h on every tier). |
quota_seconds_limit | integer | Per-tier time cap for the current window. 0 for paid (unmetered). |
404 session not found.
See also
tunnelbyte- CLI driver that wraps these endpoints and renders the live status line.- Tiers - per-tier daily caps and per-session caps.