Skip to main content
Flowxi returns structured, deterministic JSON errors designed for frontend-safe control, anti-enumeration, and bank-level UX consistency. Errors are part of the API contract.
They are stable, localized, and intentionally explicit so the frontend can react without guessing or parsing messages.
Every error response is produced either by:
  • global exception handling (bootstrap/app.php)
  • domain controllers (auth, 2FA, registration, etc.)

Error contract (guaranteed)

Every error response follows one of the formats below.

Standard error shape

{
  "message": "Human readable message",
  "code": "ERROR_CODE"
}
Properties:
  • code Stable, machine-readable identifier. Never localized. Never changes.
  • message Human-readable explanation, always localized.
  • HTTP status Meaningful and intentional (see mapping below).

Validation error (HTTP 422)

Used exclusively for request validation failures.
{
  "message": "Some fields are invalid.",
  "code": "VALIDATION_FAILED",
  "errors": {
    "email": [
      "The email must be a valid email address."
    ],
    "password": [
      "The password must be at least 8 characters."
    ]
  }
}
Properties:
  • errors is a field → array of messages map
  • messages are localized
  • field names are never localized
  • structure is stable across all endpoints
Frontend must treat validation errors as form-level, not global failures.

Localization of errors

Errors use the same locale resolution middleware as the rest of the API. Resolution order:
  1. X-App-Locale header (recommended)
  2. Accept-Language
  3. user.locale (authenticated requests)
  4. fallback: fr
Localization applies to:
  • message
  • validation messages inside errors
  • emails triggered during the request
code values are never localized and must always be used for logic.

HTTP status semantics (contract)

HTTP statusMeaningFrontend responsibility
422Invalid request payloadShow inline field errors
401Unauthenticated / invalid sessionClear token, redirect to login
403Forbidden / invalid verificationStay in flow, show error
404Resource not foundShow not-found or restart flow
409Conflict (state or business rule)Propose alternative path
410Gone (expired challenge / token)Restart the related flow
429Rate limitedDisable action, show cooldown
500Server error (production-safe)Show generic retry UI
This mapping is intentional and consistent across the platform.

Global errors (from exception handling)

These errors can occur on any endpoint.

Validation failed

HTTP: 422 Code: VALIDATION_FAILED
{
  "message": "Some fields are invalid.",
  "code": "VALIDATION_FAILED",
  "errors": {
    "email": ["The email must be a valid email address."]
  }
}
Frontend guidance:
  • Render field-level errors next to inputs
  • Do not show multiple global toasts
  • Do not retry automatically

Unauthenticated

HTTP: 401 Code: UNAUTHENTICATED
{
  "message": "Unauthenticated.",
  "code": "UNAUTHENTICATED"
}
Frontend guidance:
  • Clear stored token
  • Reset user state
  • Redirect to login or onboarding entry point

Rate limited

HTTP: 429 Code: RATE_LIMITED
{
  "message": "Too many attempts. Try again later.",
  "code": "RATE_LIMITED"
}
Frontend guidance:
  • Disable the triggering action
  • Show cooldown or timer
  • Never retry automatically in a loop

Server error (production)

HTTP: 500 Code: SERVER_ERROR
{
  "message": "Something went wrong. Try again later.",
  "code": "SERVER_ERROR"
}
Frontend guidance:
  • Show generic error UI
  • Offer a retry action
  • Log client-side context if available
Stack traces are never exposed in production.

Authentication errors (anti-enumeration)

Authentication endpoints are deliberately strict.

Invalid credentials

Returned for all of the following cases:
  • unknown email
  • wrong password
  • account not in active state
HTTP: 401 Code: INVALID_CREDENTIALS
{
  "message": "Invalid credentials.",
  "code": "INVALID_CREDENTIALS"
}
Frontend rules:
  • Never indicate which field failed
  • Never suggest account existence
  • Optional UX: show “Forgot password?” only if implemented
This behavior is non-negotiable.
These errors occur during login or 2FA management.
CodeHTTPMeaning
MFA_REQUIRED200Second factor required (challenge issued)
MFA_CHALLENGE_GONE410Challenge expired or missing
MFA_CHALLENGE_INVALID400Challenge binding mismatch (IP / UA / device)
MFA_CODE_INVALID403Wrong TOTP code
MFA_TOO_MANY_ATTEMPTS429Too many attempts on the same challenge
Frontend guidance:
  • Restart login on MFA_CHALLENGE_GONE
  • Do not retry automatically
  • Lock UI on MFA_TOO_MANY_ATTEMPTS

Registration & onboarding errors

CodeHTTPMeaning
EMAIL_ALREADY_USED409Email already belongs to active account
EMAIL_ALREADY_ACTIVE409Account already activated
USER_NOT_FOUND404No user for resend flow
OTP_INVALID422/403Invalid or expired email code
MAGIC_LINK_INVALID403Expired or invalid magic link
Frontend guidance:
  • Always propose the next valid step
  • Never reveal internal state
  • Restart flows cleanly when needed

Frontend best practices (mandatory)

  • Always branch logic on code, never on message
  • Treat 429 as a product constraint, not a bug
  • Never expose backend internals to users
  • Never infer account existence from errors
  • Assume all messages are localized

Guarantees

Flowxi error handling guarantees:
  • stable and documented error codes
  • deterministic HTTP statuses
  • strict anti-enumeration
  • full localization coverage
  • production-safe responses only
If the frontend respects this contract, no guesswork is required.

Testing checklist

  • Verify identical responses for wrong email vs wrong password
  • Trigger validation errors and inspect errors structure
  • Hit rate limits and ensure UI cooldown
  • Test expired MFA challenges
  • Switch X-App-Locale and verify translated messages