Auth Endpoints

Register new accounts, authenticate users, retrieve the current user profile, and revoke access tokens. These endpoints issue and revoke the Sanctum bearer tokens used to authorize every other API request.

The token returned by Register and Login is a Sanctum personal access token (named API Token). Send it as Authorization: Bearer <token> on all authenticated endpoints. The four auth endpoints return flat, bespoke JSON — they do not use the {success, payload, meta, errors, description} envelope that the resource endpoints (sub-users, presets, descriptors, ISP proxies) use.

Registration & Login

POST /v1/auth/register

Register

Register

Create a new user account and receive an access token in the same response, so you can start making authenticated requests without a separate login call.

Example request:
Request Body
Name Type Required Description
email string Required A valid email address, max 255 characters. Must be unique across all accounts.
password string Required The account password. Minimum 8 characters and must contain mixed case (upper + lower) and at least one number.
password_confirmation string Required Must match the password field exactly.
name string Optional Display name. If omitted, a name is derived from the email local-part.
referral_code string Optional Referral code of the referring user, max 64 characters.
curl -X POST https://api.proxyhat.com/v1/auth/register \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john@example.com",
    "password": "Secret1234",
    "password_confirmation": "Secret1234"
  }'
import requests

response = requests.post(
    "https://api.proxyhat.com/v1/auth/register",
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
    json={
        "name": "John Doe",
        "email": "john@example.com",
        "password": "Secret1234",
        "password_confirmation": "Secret1234",
    },
)

data = response.json()
print(data["accessToken"])
const response = await fetch("https://api.proxyhat.com/v1/auth/register", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/json",
  },
  body: JSON.stringify({
    name: "John Doe",
    email: "john@example.com",
    password: "Secret1234",
    password_confirmation: "Secret1234",
  }),
});

const data = await response.json();
console.log(data.accessToken);
payload := strings.NewReader(`{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "Secret1234",
  "password_confirmation": "Secret1234"
}`)

req, _ := http.NewRequest("POST", "https://api.proxyhat.com/v1/auth/register", payload)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["accessToken"])

Password rules are enforced server-side: at least 8 characters, mixed case, and at least one number. A weak password returns 422 with Laravel validation errors, e.g. {"message": "...", "errors": {"password": ["The password field must contain at least one uppercase and one lowercase letter."]}}. A duplicate email returns 422 with an email error.

POST /v1/auth/login

Login

Login

Authenticate with email and password to receive an access token. Use the returned token as a Bearer token in the Authorization header for all subsequent API requests.

Example request:
Request Body
Name Type Required Description
email string Required The email address associated with the account.
password string Required The account password.
twofa_code string Optional Two-factor code, max 16 chars. Required only if the account has 2FA enabled. Accepts a TOTP code or a one-time recovery code.
curl -X POST https://api.proxyhat.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "email": "john@example.com",
    "password": "Secret1234"
  }'
import requests

response = requests.post(
    "https://api.proxyhat.com/v1/auth/login",
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
    json={
        "email": "john@example.com",
        "password": "Secret1234",
    },
)

data = response.json()
api_key = data["accessToken"]
print(f"Token: {api_key}")
const response = await fetch("https://api.proxyhat.com/v1/auth/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/json",
  },
  body: JSON.stringify({
    email: "john@example.com",
    password: "Secret1234",
  }),
});

const data = await response.json();
console.log(`Token: ${data.accessToken}`);
payload := strings.NewReader(`{
  "email": "john@example.com",
  "password": "Secret1234"
}`)

req, _ := http.NewRequest("POST", "https://api.proxyhat.com/v1/auth/login", payload)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println("Token:", result["accessToken"])

Login error responses

Login uses HTTP status codes rather than the success envelope, but the 2FA branches return an envelope-shaped body:

401 — invalid credentials. Flat body: {"message": "Unauthorized"}.

403 — 2FA required. Returned when the account has 2FA enabled and no twofa_code was supplied:

Response 403
{
  "success": false,
  "payload": null,
  "errors": [],
  "description": "2FA verification required",
  "requires_2fa": true
}

422 — invalid 2FA code. Returned when a twofa_code was supplied but is wrong (and is not a valid recovery code):

Response 422
{
  "success": false,
  "payload": null,
  "errors": { "twofa_code": ["Invalid 2FA code"] },
  "description": "Invalid 2FA code"
}

Current User

GET /v1/auth/user Requires Auth

Get Current User

Get Current User

Retrieve the authenticated user, their traffic balance breakdown, preferences, admin roles/permissions, account restriction status, and feature-access flags. This is the primary "who am I / how much traffic do I have" endpoint.

No input needed — runs live with your key
curl https://api.proxyhat.com/v1/auth/user \
  -H "Authorization: Bearer __API_KEY__" \
  -H "Accept: application/json"
import requests

response = requests.get(
    "https://api.proxyhat.com/v1/auth/user",
    headers={
        "Authorization": "Bearer __API_KEY__",
        "Accept": "application/json",
    },
)

user = response.json()
print(f"{user[\"name\"]} — {user[\"traffic\"][\"total_human\"]} total")
const response = await fetch("https://api.proxyhat.com/v1/auth/user", {
  headers: {
    "Authorization": "Bearer __API_KEY__",
    "Accept": "application/json",
  },
});

const user = await response.json();
console.log(`${user.name} — ${user.traffic.total_human} total`);
req, _ := http.NewRequest("GET", "https://api.proxyhat.com/v1/auth/user", nil)
req.Header.Set("Authorization", "Bearer __API_KEY__")
req.Header.Set("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var user map[string]interface{}
json.NewDecoder(resp.Body).Decode(&user)
fmt.Println(user["name"], user["traffic"])

This response is not enveloped — the fields are top-level. Notes on the shape:

  • traffic mixes the current allowance (regular_bytes / subscription_bytes / total_bytes, each with a human-readable twin) with usage (used_bytes, peak_bytes, percent_remaining) and subscription state (subscription, subscription_expires_at, auto_renew, pending_plan, in_grace_period, has_billing_portal). For an account with no active subscription these subscription fields are null/false as shown.
  • roles and permissions are admin RBAC arrays — empty for ordinary customer accounts.
  • restriction is null unless the account has an active restriction; when present it is an object with flags, reason, is_permanent, expires_at, is_full_ban, coupons_disabled, and referrals_disabled.
  • referral_bonus is null unless the account was referred and has not yet made a first purchase; when present it is { "is_referee": true, "bonus_percent": <n>, "status": "pending" }.
  • has_isp_proxy_access and premium_theme_access are boolean feature flags.

Session Management

POST /v1/auth/logout Requires Auth

Logout

Logout

Revoke the access token used on the request. After this call the token is deleted and can no longer authenticate future requests. Responds with HTTP 204 and no response body.

Example request:
curl -X POST https://api.proxyhat.com/v1/auth/logout \
  -H "Authorization: Bearer __API_KEY__" \
  -H "Accept: application/json"
import requests

response = requests.post(
    "https://api.proxyhat.com/v1/auth/logout",
    headers={
        "Authorization": "Bearer __API_KEY__",
        "Accept": "application/json",
    },
)

# 204 No Content — the token is now revoked
print(response.status_code)
const response = await fetch("https://api.proxyhat.com/v1/auth/logout", {
  method: "POST",
  headers: {
    "Authorization": "Bearer __API_KEY__",
    "Accept": "application/json",
  },
});

// 204 No Content — the token is now revoked
console.log(response.status);
req, _ := http.NewRequest("POST", "https://api.proxyhat.com/v1/auth/logout", nil)
req.Header.Set("Authorization", "Bearer __API_KEY__")
req.Header.Set("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

// 204 No Content — the token is now revoked
fmt.Println(resp.StatusCode)

Logout returns 204 No Content, so treat it as success by status code — do not parse a JSON body. It revokes only the token presented on the request; other tokens issued to the account remain valid.