Error Handling

Understand the error format, HTTP status codes, and how to handle errors gracefully in your application.

Error Response Format

When an API request fails, the response follows the standard envelope with success: false:

{
  "success": false,
  "payload": null,
  "errors": {
    "field_name": ["Error message for this field"]
  },
  "description": "Validation failed"
}

HTTP Status Codes

Code Meaning Description
200 OK Request succeeded. Response contains the requested data.
201 Created Resource was created successfully.
204 No Content Request succeeded with no response body (e.g., logout).
400 Bad Request The request was malformed or missing required fields.
401 Unauthorized Missing or invalid authentication token.
403 Forbidden Authenticated but not authorized (e.g., 2FA required).
404 Not Found The requested resource does not exist.
422 Validation Error Request body failed validation. Check the errors object.
429 Rate Limited Too many requests. Wait and retry after Retry-After seconds.
500 Internal Error Server error. Contact support if this persists.

Validation Errors (422)

When request validation fails, the errors field contains a map of field names to arrays of error messages:

{
  "success": false,
  "payload": null,
  "errors": {
    "email": ["The email field is required."],
    "password": [
      "The password field is required.",
      "The password must be at least 8 characters."
    ]
  },
  "description": "Validation failed"
}

Rate Limiting (429)

When rate limited, the response includes a Retry-After header indicating how many seconds to wait:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{
  "message": "Too Many Attempts."
}
Tip: Implement exponential backoff in your client to handle rate limits gracefully. Check the X-RateLimit-Remaining header to proactively slow down before hitting the limit.

Handling Errors in Code

# Check the HTTP status code
curl -s -o response.json -w "%{http_code}" \
  https://api.proxyhat.com/v1/auth/user \
  -H "Authorization: Bearer __API_KEY__"
import requests

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

if response.status_code == 200:
    data = response.json()
    print(data["payload"])
elif response.status_code == 401:
    print("Invalid API key")
elif response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 60))
    print(f"Rate limited. Retry after {retry_after}s")
else:
    print(f"Error {response.status_code}: {response.text}")
const response = await fetch("https://api.proxyhat.com/v1/auth/user", {
  headers: { "Authorization": "Bearer __API_KEY__" },
});

if (response.ok) {
  const data = await response.json();
  console.log(data.payload);
} else if (response.status === 401) {
  console.error("Invalid API key");
} else if (response.status === 429) {
  const retryAfter = response.headers.get("Retry-After") || 60;
  console.error(`Rate limited. Retry after ${retryAfter}s`);
} else {
  console.error(`Error ${response.status}`);
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

switch resp.StatusCode {
case 200:
    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    fmt.Println(result["payload"])
case 401:
    fmt.Println("Invalid API key")
case 429:
    retryAfter := resp.Header.Get("Retry-After")
    fmt.Printf("Rate limited. Retry after %ss\n", retryAfter)
default:
    fmt.Printf("Error %d\n", resp.StatusCode)
}