Skip to content

YeboID Error Handling ​

Consistent error responses across all endpoints.


Error Response Format ​

All errors follow this structure:

json
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message",
    "details": { }
  }
}
FieldTypeDescription
codestringMachine-readable error code (UPPER_SNAKE_CASE)
messagestringHuman-readable description
detailsobjectAdditional context (optional)

Error Categories ​

4xx Client Errors ​

Errors caused by the client request.

5xx Server Errors ​

Errors caused by server issues.


Complete Error Code Reference ​

Authentication Errors (AUTH_*) ​

CodeHTTPMessageWhen
AUTH_INVALID_PHONE400Invalid phone number formatPhone doesn't match E.164
AUTH_INVALID_PIN400PIN must be 4-6 digitsPIN format wrong
AUTH_INVALID_OTP400Invalid verification codeWrong OTP entered
AUTH_OTP_EXPIRED400Verification code has expiredOTP past expiry
AUTH_INVALID_CREDENTIALS401Invalid phone or PINWrong login credentials
AUTH_INVALID_TOKEN401Invalid access tokenToken malformed/tampered
AUTH_TOKEN_EXPIRED401Access token has expiredToken past expiry
AUTH_INVALID_REFRESH_TOKEN401Invalid refresh tokenRefresh token invalid
AUTH_REFRESH_TOKEN_EXPIRED401Refresh token has expiredRefresh token past expiry
AUTH_TEMP_TOKEN_INVALID400Invalid or expired verificationTemp token from OTP verify invalid
AUTH_ACCOUNT_LOCKED403Account temporarily lockedToo many failed PIN attempts
AUTH_ACCOUNT_NOT_FOUND404Account not foundPhone not registered
AUTH_PHONE_EXISTS409Phone number already registeredSignup with existing phone
AUTH_OTP_RATE_LIMITED429Too many OTP requestsExceeded OTP send limit
AUTH_SIGNIN_RATE_LIMITED429Too many sign in attemptsExceeded signin attempts

User Errors (USER_*) ​

CodeHTTPMessageWhen
USER_NOT_FOUND404User not foundUser doesn't exist
USER_PROFILE_INVALID400Invalid profile dataProfile update validation failed
USER_DELETE_PIN_REQUIRED400PIN required to delete accountMissing PIN for deletion
USER_DELETE_CONFIRMATION400Confirmation text requiredMissing "DELETE MY ACCOUNT"

Handle Errors (HANDLE_*) ​

CodeHTTPMessageWhen
HANDLE_INVALID_FORMAT400Handle must be 3-30 lowercase letters, numbers, or underscoresBad format
HANDLE_INVALID_EDGES400Handle cannot start or end with underscorehandle or handle
HANDLE_TAKEN409This handle is already takenSomeone else has it
HANDLE_RESERVED409This handle is reservedIn reserved list
HANDLE_COOLDOWN429You can change your handle again on30-day cooldown
HANDLE_CHECK_RATE_LIMITED429Too many handle checksExceeded check limit

Session Errors (SESSION_*) ​

CodeHTTPMessageWhen
SESSION_NOT_FOUND404Session not foundInvalid session ID
SESSION_ALREADY_REVOKED400Session already revokedDouble revocation

KYC Errors (KYC_*) ​

CodeHTTPMessageWhen
KYC_ALREADY_VERIFIED400Account is already verifiedRe-initiating KYC
KYC_PENDING400Verification already in progressRe-initiating while pending
KYC_REJECTED403Verification was rejectedAccess after rejection

General Errors ​

CodeHTTPMessageWhen
INVALID_REQUEST400Invalid request bodyMalformed JSON
MISSING_FIELD400Missing required field:Required field absent
INVALID_FIELD400Invalid value for field:Field validation failed
UNAUTHORIZED401Authentication requiredNo token provided
FORBIDDEN403You don't have permissionInsufficient permissions
NOT_FOUND404Resource not foundGeneric 404
RATE_LIMITED429Too many requestsGeneric rate limit
INTERNAL_ERROR500Something went wrongServer error
SERVICE_UNAVAILABLE503Service temporarily unavailableMaintenance/overload

Error Details ​

Some errors include additional context in the details field:

Validation Errors ​

json
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Validation failed",
    "details": {
      "fields": [
        {
          "field": "phone",
          "message": "Must be in E.164 format"
        },
        {
          "field": "pin",
          "message": "Must be 4-6 digits"
        }
      ]
    }
  }
}

Rate Limit Errors ​

json
{
  "success": false,
  "error": {
    "code": "AUTH_OTP_RATE_LIMITED",
    "message": "Too many OTP requests",
    "details": {
      "limit": 3,
      "window": "1 hour",
      "retry_after": 2400
    }
  }
}

Account Locked ​

json
{
  "success": false,
  "error": {
    "code": "AUTH_ACCOUNT_LOCKED",
    "message": "Account temporarily locked",
    "details": {
      "locked_until": "2026-03-18T21:00:00Z",
      "unlock_method": "wait or reset PIN via OTP"
    }
  }
}

Handle Cooldown ​

json
{
  "success": false,
  "error": {
    "code": "HANDLE_COOLDOWN",
    "message": "You can change your handle again on April 18, 2026",
    "details": {
      "next_change_available": "2026-04-18T20:00:00Z",
      "days_remaining": 30
    }
  }
}

HTTP Status Code Summary ​

StatusMeaningCommon Codes
200OKSuccess
201CreatedAccount created
400Bad RequestValidation errors
401UnauthorizedAuth required/failed
403ForbiddenLocked/no permission
404Not FoundResource doesn't exist
409ConflictAlready exists
429Too Many RequestsRate limited
500Server ErrorInternal error
503UnavailableMaintenance

Client Handling ​

JavaScript Example ​

javascript
async function signIn(phone, pin) {
  try {
    const res = await fetch('/auth/signin', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ phone, pin })
    });
    
    const data = await res.json();
    
    if (!data.success) {
      switch (data.error.code) {
        case 'AUTH_INVALID_CREDENTIALS':
          showError('Wrong phone or PIN');
          break;
        case 'AUTH_ACCOUNT_LOCKED':
          const until = data.error.details.locked_until;
          showError(`Account locked until ${formatDate(until)}`);
          break;
        case 'AUTH_ACCOUNT_NOT_FOUND':
          showError('No account with this phone. Sign up?');
          break;
        default:
          showError(data.error.message);
      }
      return null;
    }
    
    return data.data;
  } catch (e) {
    showError('Network error. Try again.');
    return null;
  }
}

React Hook Example ​

jsx
function useYeboIDError() {
  const handleError = (error) => {
    const messages = {
      'AUTH_INVALID_CREDENTIALS': 'Wrong phone or PIN',
      'AUTH_ACCOUNT_LOCKED': 'Account locked. Try again later.',
      'HANDLE_TAKEN': 'This handle is already taken',
      'RATE_LIMITED': 'Too many attempts. Slow down.',
    };
    
    return messages[error.code] || error.message;
  };
  
  return { handleError };
}

Logging & Monitoring ​

Error Logging (Server-side) ​

All errors are logged with:

  • Request ID
  • User ID (if authenticated)
  • IP address
  • Error code
  • Stack trace (5xx only)

Alerting ​

ConditionAlert
5xx rate > 1%PagerDuty
429 rate > 10%Slack
AUTH_ACCOUNT_LOCKED spikeSlack

Last updated: March 18, 2026

One chat. Everything done.