Error Reference

Complete reference for OrbVPN API error codes, HTTP status codes, and best practices for error handling across REST, gRPC, and WebSocket protocols.

API Reference

Error Reference

Every OrbVPN API response follows a predictable structure. Learn how to interpret error codes, handle failures gracefully, and build resilient integrations.


Standard Response Format

All OrbVPN API endpoints return a consistent JSON envelope. The success field tells you immediately whether the request succeeded, so you can branch your logic without inspecting HTTP status codes.

Success Response

The request completed successfully. The response body contains a data field with the requested resource or confirmation.

Error Response

The request failed. The response body contains an error object with a machine-readable code, a human-readable message, and optional details.

Success Response

200Successful request
{
  "success": true,
  "data": {
    "id": "usr_abc123",
    "email": "user@example.com",
    "subscription": {
      "plan": "premium",
      "status": "active",
      "expiresAt": "2027-01-15T00:00:00Z"
    }
  }
}

Error Response

400Failed request
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request body contains invalid fields.",
    "details": {
      "field": "email",
      "constraint": "required",
      "received": null
    }
  }
}

Consistent Envelope

Every response -- success or error -- is wrapped in the same top-level structure. Always check the success boolean first, then read either data or error accordingly.


HTTP Status Codes

The API uses standard HTTP status codes to indicate the general category of a response. The table below covers every status code you may encounter.

StatusNameDescription
200OKThe request succeeded. Response body contains the requested data.
201CreatedA new resource was created successfully. Response body contains the new resource.
204No ContentThe request succeeded but there is no response body (e.g., after a DELETE).
400Bad RequestThe request is malformed or contains invalid parameters. Check the details field.
401UnauthorizedAuthentication is missing or the provided token is invalid or expired.
403ForbiddenThe authenticated user does not have permission to perform this action.
404Not FoundThe requested resource does not exist or has been deleted.
409ConflictThe request conflicts with the current state of the resource (e.g., duplicate email).
422Unprocessable EntityThe request is well-formed but semantically invalid (e.g., weak password).
429Too Many RequestsYou have exceeded the rate limit. See the Rate Limiting Guide.
500Internal Server ErrorAn unexpected error occurred on the server. Retry with exponential backoff.
502Bad GatewayAn upstream service returned an invalid response. Usually transient.
503Service UnavailableThe service is temporarily down for maintenance or overloaded. Retry later.

Do Not Rely Solely on HTTP Status Codes

Always inspect the error.code field in the response body for precise error identification. Multiple distinct error conditions can share the same HTTP status code (e.g., both TOKEN_EXPIRED and TOKEN_INVALID return 401).


Application Error Codes

Every error response includes a machine-readable error.code string. Use these codes to build precise error-handling logic in your application.

Authentication Errors

CodeHTTP StatusDescription
AUTH_REQUIRED401No authentication token was provided. Include a valid Bearer token in the Authorization header.
TOKEN_EXPIRED401The access token has expired. Use your refresh token to obtain a new access token.
TOKEN_INVALID401The token is malformed, revoked, or was signed with an unknown key. Re-authenticate.
INSUFFICIENT_PERMISSIONS403The authenticated user does not have the required role or permission for this endpoint.
401Expired token error
{
  "success": false,
  "error": {
    "code": "TOKEN_EXPIRED",
    "message": "Your access token has expired. Please refresh your token or re-authenticate.",
    "details": {
      "expiredAt": "2026-02-08T11:30:00Z",
      "tokenType": "access"
    }
  }
}

Validation Errors

CodeHTTP StatusDescription
VALIDATION_ERROR400One or more request fields failed validation. The details object specifies which fields are invalid.
INVALID_EMAIL422The provided email address is not a valid email format.
WEAK_PASSWORD422The password does not meet the minimum strength requirements (at least 8 characters, one uppercase, one number).
422Weak password error
{
  "success": false,
  "error": {
    "code": "WEAK_PASSWORD",
    "message": "Password does not meet strength requirements.",
    "details": {
      "requirements": [
        "Minimum 8 characters",
        "At least one uppercase letter",
        "At least one number",
        "At least one special character"
      ],
      "failedChecks": ["uppercase", "special_character"]
    }
  }
}

Resource Not Found Errors

CodeHTTP StatusDescription
USER_NOT_FOUND404No user exists with the specified ID or email.
SERVER_NOT_FOUND404The requested VPN server does not exist or has been decommissioned.
DEVICE_NOT_FOUND404No device exists with the specified device ID.
SUBSCRIPTION_NOT_FOUND404No active subscription was found for the user.

Conflict Errors

CodeHTTP StatusDescription
EMAIL_ALREADY_EXISTS409An account with this email address already exists. Use the login endpoint instead.
DEVICE_LIMIT_REACHED409The user has reached the maximum number of registered devices for their subscription plan.
409Device limit reached
{
  "success": false,
  "error": {
    "code": "DEVICE_LIMIT_REACHED",
    "message": "You have reached the maximum number of devices for your plan.",
    "details": {
      "currentDevices": 5,
      "maxDevices": 5,
      "plan": "standard",
      "upgradeUrl": "https://orbvpn.com/pricing"
    }
  }
}

Rate Limiting and Quota Errors

CodeHTTP StatusDescription
RATE_LIMITED429Too many requests in a given time window. Respect the X-RateLimit-Reset header.
QUOTA_EXCEEDED429The monthly or daily API quota for your plan has been exceeded. Upgrade or wait for reset.

Server Errors

CodeHTTP StatusDescription
INTERNAL_ERROR500An unexpected server error occurred. The OrbVPN team is automatically notified.
SERVICE_UNAVAILABLE503The service is temporarily unavailable due to maintenance or overload.
UPSTREAM_ERROR502An upstream dependency returned an unexpected response. Usually transient.

VPN-Specific Errors

CodeHTTP StatusDescription
VPN_CONNECTION_FAILED500The VPN server could not establish a tunnel. The server may be at capacity or experiencing issues.
DNS_RESOLUTION_FAILED500Smart DNS resolution failed for the requested domain. Verify the domain is in the supported list.

Billing and Payment Errors

CodeHTTP StatusDescription
PAYMENT_FAILED400The payment could not be processed. Check the payment method and try again.
SUBSCRIPTION_EXPIRED403The user's subscription has expired. A valid subscription is required for this endpoint.
INSUFFICIENT_BALANCE400The user's wallet balance is insufficient for this transaction.
403Subscription expired
{
  "success": false,
  "error": {
    "code": "SUBSCRIPTION_EXPIRED",
    "message": "Your subscription has expired. Please renew to continue using this feature.",
    "details": {
      "expiredAt": "2026-01-31T23:59:59Z",
      "plan": "premium",
      "renewUrl": "https://orbvpn.com/dashboard/subscription"
    }
  }
}

Error Handling Best Practices

Follow these practices to build resilient integrations that handle errors gracefully.

1

Always Check the success Field

Before accessing data, verify that success is true. This is the fastest and most reliable way to determine if a request succeeded.

2

Use Error Codes, Not Messages

Build your conditional logic around the error.code field (e.g., TOKEN_EXPIRED), not the human-readable message string. Messages may change between API versions; codes are stable.

3

Implement Retry Logic with Exponential Backoff

For transient errors (500, 502, 503, 429), retry the request with exponential backoff. Start with a 1-second delay and double it on each attempt, up to a maximum of 32 seconds.

4

Handle Token Expiration Automatically

When you receive TOKEN_EXPIRED, use your refresh token to obtain a new access token, then retry the original request. Do not prompt the user to log in again unless the refresh also fails.

5

Log Error Details for Debugging

Always log the full error object, including the details field. This information is invaluable for debugging validation failures and understanding exactly what went wrong.

Retry Strategy: Exponential Backoff

For transient errors, implement exponential backoff with jitter to avoid thundering-herd problems.

Attempt 1: wait 1s + random(0-500ms)
Attempt 2: wait 2s + random(0-500ms)
Attempt 3: wait 4s + random(0-500ms)
Attempt 4: wait 8s + random(0-500ms)
Attempt 5: wait 16s + random(0-500ms)
Max retries: 5 | Max delay: 32s

Retryable Errors

500 (Internal Error), 502 (Bad Gateway), 503 (Service Unavailable), and 429 (Rate Limited) are safe to retry with backoff.

Non-Retryable Errors

400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found), 409 (Conflict), and 422 (Unprocessable Entity) will not resolve with retries.

Token Refresh Flow

On 401 TOKEN_EXPIRED, refresh the token first, then retry the original request exactly once. If the refresh fails, re-authenticate.


Error Handling Code Examples

Complete examples showing robust error handling in four languages.

# Make a request and handle the response
response=$(curl -s -w "\n%{http_code}" \
  -X GET https://api.orbai.world/api/v1/users/me \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json")

# Extract HTTP status code and body
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

case $http_code in
  200)
    echo "Success: $(echo $body | jq '.data')"
    ;;
  401)
    error_code=$(echo $body | jq -r '.error.code')
    if [ "$error_code" = "TOKEN_EXPIRED" ]; then
      echo "Token expired. Refreshing..."
      # Call refresh endpoint
      refresh_response=$(curl -s -X POST \
        https://api.orbai.world/api/v1/auth/refresh \
        -H "Content-Type: application/json" \
        -d "{\"refreshToken\": \"$REFRESH_TOKEN\"}")
      ACCESS_TOKEN=$(echo $refresh_response | jq -r '.data.token')
      # Retry original request with new token
    else
      echo "Auth error: $error_code"
    fi
    ;;
  429)
    reset=$(echo "$response" | grep -i "X-RateLimit-Reset" | cut -d' ' -f2)
    echo "Rate limited. Retry after: $reset"
    ;;
  *)
    echo "Error $http_code: $(echo $body | jq -r '.error.message')"
    ;;
esac

Common Error Scenarios

Missing Authorization Header

Every protected endpoint requires Authorization: Bearer <token>. If omitted, you will receive AUTH_REQUIRED (401).

Expired Access Token

Access tokens expire after 24 hours. Call POST /api/v1/auth/refresh with your refresh token to get a new one.

Validation Failures

Read the details object carefully. It specifies the exact field, constraint, and received value that caused the error.

Rate Limiting

If you receive RATE_LIMITED (429), check the X-RateLimit-Reset header and wait before retrying. See the Rate Limiting Guide.

Debugging Tips

Include a unique X-Request-ID header with each request. If you need to contact support about an error, provide this ID so the team can trace the request through our logs.


Need Help?

If you encounter an error that is not listed here or need assistance debugging an integration issue, reach out to our developer support team.

Contact Support