Skip to main content
The CLI is what you talk to. The API is what the CLI talks to. Same endpoints, same auth, same JSON.

Base URL

https://api.tunnelbyte.dev/v1

Auth

Single bearer token in the Authorization header:
curl -H "Authorization: Bearer $TB_KEY" https://api.tunnelbyte.dev/v1/usage
The CLI’s token is the API token - there is no separate API-key surface.

Loading your token into the shell

After running tunnelbyte upgrade (or tunnelbyte signup for the free tier), the token is cached in your config dir. The portable way to load it into TB_KEY is:
export TB_KEY=$(tunnelbyte token)
If tunnelbyte isn’t on the machine (e.g. a CI runner where you’ve shipped the raw token only), fall back to reading the cache file directly:
export TB_KEY=$(cat "$HOME/Library/Application Support/tunnelbyte/token")
For CI, copy the token to your secret store once (tunnelbyte token | pbcopy on macOS) and inject it as TB_KEY.

Tier-specific notes

  • Paid tier: token is account-linked, portable across machines via tunnelbyte login.
  • Anonymous tier: token is bound to the installing machine’s fingerprint and only works from there. The API works the same way, but reusing an anonymous token from a different machine fails.
Two endpoints are public (no auth): GET /v1/regions and GET /v1/ip/{addr}. Webhooks (Stripe) use signature auth, not bearer tokens.

Endpoints

EndpointAuthPurpose
GET /v1/regionspublicList active exit regions.
POST /v1/sessionsbearerCreate a session; receive a WireGuard config.
GET /v1/sessions/{id}bearerStatus of an active session.
GET /v1/usagebearerCurrent-period usage and tier.
GET /v1/ip/{addr}publicIP attribution lookup.

Versioning

The API is versioned in the URL path (/v1/...). Breaking changes ship under /v2/.... We don’t break v1.

Rate limits

  • Public endpoints: 10 burst / 1 rps per source IP, in-memory.
  • Bearer-auth endpoints: per-token caps tied to your tier (tiers).
A 429 response carries a Retry-After header (seconds). Back off and retry - don’t hammer.

Errors

JSON { "error": "<short message>" } with the appropriate HTTP status. Common ones:
StatusMeaning
400Invalid input (bad region, malformed IP, etc.).
401Missing or invalid bearer token.
403Token is valid but the requested operation is above your tier.
404Resource (e.g. session id) doesn’t exist.
429Rate-limited or quota-exhausted. Check Retry-After.
503No active node in the requested region. Try another.

See also