All Login APIs are protected by rate limiting to prevent abuse. Exceeding these limits will result in temporary request blocking.
| Endpoint | Limit Type | Limit | Period | Error Code |
|---|---|---|---|---|
POST /push_notification |
Per IP | 10 requests | 5 minutes | 1022 |
| Per Client ID | 5 requests | 5 minutes | 1023 | |
POST /verify_token |
Per IP | 10 requests | 5 minutes | 1024 |
| Per Token | 5 requests | 5 minutes | 1025 |
Client accounts are automatically locked after multiple failed login attempts to protect against brute force attacks.
| Lock Type | Trigger | Duration | Error Code | Error Message |
|---|---|---|---|---|
| Temporary Lock | 5 failed attempts | 15 minutes | 1016 | Account temporarily locked. Try again in X minutes. |
| Permanent Lock | 10 failed attempts | Until admin unlocks | 1017 | Account permanently locked. Please contact administrator. |
To accurately track your users' device and browser information in the Login Tracker, your backend must forward the browser's headers to our API.
When your backend calls our API, we see your server's information (Ruby, PHP, Node.js, Docker IP). To track the actual user's browser and IP, forward these headers:
| Header Name | Description | Example Value |
|---|---|---|
X-Forwarded-For |
User's real IP address | 203.113.45.67 |
X-Browser-User-Agent |
User's browser User-Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0 |
Implementation Examples:
Ruby (Rails/Sinatra):
require 'rest-client'
# Extract browser info from incoming request
browser_ip = request.ip
browser_ua = request.user_agent
# Forward to Axiam API
response = RestClient.post(
'https://axiam.io/api/v1/facial_sign_on/login/push_notification',
{ id: client_id }.to_json,
{
'Authorization' => "Bearer #{bearer_token}",
'Content-Type' => 'application/json',
'X-Forwarded-For' => browser_ip,
'X-Browser-User-Agent' => browser_ua
}
)
PHP (Laravel/Symfony):
$browserIp = $_SERVER['REMOTE_ADDR'];
$browserUa = $_SERVER['HTTP_USER_AGENT'];
$ch = curl_init('https://axiam.io/api/v1/facial_sign_on/login/push_notification');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['id' => $clientId]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $bearerToken,
'Content-Type: application/json',
'X-Forwarded-For: ' . $browserIp,
'X-Browser-User-Agent: ' . $browserUa
]);
$response = curl_exec($ch);
curl_close($ch);
Node.js (Express):
const axios = require('axios');
// Extract from Express request
const browserIp = req.ip || req.connection.remoteAddress;
const browserUa = req.get('User-Agent');
// Forward to Axiam API
const response = await axios.post(
'https://axiam.io/api/v1/facial_sign_on/login/push_notification',
{ id: clientId },
{
headers: {
'Authorization': `Bearer ${bearerToken}`,
'Content-Type': 'application/json',
'X-Forwarded-For': browserIp,
'X-Browser-User-Agent': browserUa
}
}
);
Python (Django/Flask):
import requests
# Extract from Flask/Django request
browser_ip = request.remote_addr
browser_ua = request.headers.get('User-Agent')
# Forward to Axiam API
response = requests.post(
'https://axiam.io/api/v1/facial_sign_on/login/push_notification',
json={'id': client_id},
headers={
'Authorization': f'Bearer {bearer_token}',
'Content-Type': 'application/json',
'X-Forwarded-For': browser_ip,
'X-Browser-User-Agent': browser_ua
}
)
push_notification and compare_face endpoints for complete tracking.
X-Forwarded-For and X-Browser-User-Agent for accurate device tracking.
X-RateLimit-Remaining and implement backoff strategy when approaching limit.
1. Rate Limit Exceeded - Per IP (push_notification):
{
"success": false,
"code": 1020,
"message": "Rate limit exceeded",
"user_message": "Too many requests. Please try again in 45 seconds.",
"data": {
"rate_limit": {
"limit": 10,
"remaining": 0,
"reset_after": 45
}
}
}
2. Rate Limit Exceeded - Per Client ID (push_notification):
{
"success": false,
"code": 1021,
"message": "Rate limit exceeded for this account",
"user_message": "Too many login attempts for this account. Please try again in 120 seconds.",
"data": {
"rate_limit": {
"limit": 5,
"remaining": 0,
"reset_after": 120
}
}
}
3. Rate Limit Exceeded - Per IP (verify_token):
{
"success": false,
"code": 1022,
"message": "Rate limit exceeded",
"user_message": "Too many verification attempts. Please try again in 60 seconds.",
"data": {
"rate_limit": {
"limit": 10,
"remaining": 0,
"reset_after": 60
}
}
}
4. Rate Limit Exceeded - Per Token (verify_token):
{
"success": false,
"code": 1023,
"message": "Rate limit exceeded for this verification token",
"user_message": "Too many attempts with this token. Please request a new one in 90 seconds.",
"data": {
"rate_limit": {
"limit": 5,
"remaining": 0,
"reset_after": 90
}
}
}
5. Account Temporarily Locked:
{
"success": false,
"code": 1013,
"message": "Account temporarily locked",
"user_message": "Account locked due to multiple failed attempts. Please try again in 12 minutes."
}
6. Facial Service Permanently Disabled:
{
"success": false,
"code": 1041,
"message": "Facial sign-on service permanently disabled",
"user_message": "Facial sign-on has been permanently disabled for security reasons: Multiple security violations detected. Please use alternative login methods or contact support."
}
All API errors return a consistent JSON structure with an error code, message, and additional context.
{
"success": false,
"code": 1000,
"message": "Technical error description for logging",
"user_message": "User-friendly error message to display",
"data": {} // Optional: Additional context (e.g., rate_limit info)
}
Note: The message field contains technical details for debugging/logging,
while user_message contains a friendly message suitable for displaying to end users.
| Code | Error Type | Description | HTTP Status |
|---|---|---|---|
| Authentication & Authorization Errors | |||
1000 |
Unauthorized | Missing or invalid API credentials (Bearer token) | 401 |
1001 |
Forbidden | Valid credentials but insufficient permissions for requested operation | 403 |
1002 |
Authorization Error | Facial sign-on not enabled or account blocked | 403 |
1013 |
Invalid Token | Verification token is invalid, expired, or malformed | 401 |
1014 |
Token Reuse | Token already used (replay attack detected) | 401 |
1015 |
Face Mismatch | Face recognition failed - uploaded face doesn't match registered face | 401 |
| Account Lock Errors | |||
1016 |
Temporary Lock | Account locked for 15 minutes after 5 failed attempts | 403 |
1017 |
Permanent Lock | Account permanently locked after 10 failed attempts. Admin unlock required. | 403 |
| Rate Limiting Errors | |||
1022 |
Rate Limit (IP) - Push | Too many push_notification requests from same IP (10/minute limit) | 429 |
1023 |
Rate Limit (Client) - Push | Too many push_notification requests for same client (5/minute limit) | 429 |
1024 |
Rate Limit (IP) - Verify | Too many verify_token requests from same IP (20/minute limit) | 429 |
1025 |
Rate Limit (Client) - Verify | Too many verify_token requests for same client (10/minute limit) | 429 |
| Validation & Input Errors | |||
1003 |
Bad Request | Invalid request format or malformed JSON payload | 400 |
1004 |
Notification Failed | Failed to send push notification to mobile device | 500 |
1005 |
Device Not Found | Mobile device token not registered or invalid | 404 |
1006 |
Validation Error | Input validation failed (invalid email, missing required fields, etc.) | 400 |
1007 |
Not Found | Requested resource not found (client, site, user, etc.) | 404 |
1012 |
Device Token Missing | Mobile device token not found for client/site | 404 |
| Server & System Errors | |||
1008 |
Internal Server Error | Unexpected server error occurred | 500 |
1009 |
Service Unavailable | Service temporarily unavailable (maintenance, overload) | 503 |
1010 |
Database Error | Database connection or query error | 500 |
1011 |
External Service Error | Third-party service error (AWS Rekognition, FCM, etc.) | 502 |
code field along with the error message for easier debugging and support requests.