VALIDATION_FAILED | 400 | Request payload didn’t match schema | Show field errors to user |
PAYLOAD_TOO_LARGE | 413 | Body or file too big | Reduce size and retry |
UNAUTHENTICATED | 401 | Token missing/invalid/expired | Refresh, then retry once; on second 401, log out |
TOKEN_REVOKED | 401 | Refresh token reused or logout-all invoked | Log out, redirect to login |
INVALID_CODE | 401 | 6-digit OTP digits are wrong (attempts++) | Re-prompt; show attempts remaining |
CODE_EXPIRED | 401 | OTP expired, consumed, attempt-capped, or email unknown | Request a fresh code via /resend-verify-email |
OAUTH_INVALID_TOKEN | 401 | Social-login ID token failed verification (malformed, expired, wrong project) or carried no email | Re-run native sign-in to mint a fresh token |
PAYWALL_REQUIRED | 402 | Subscription required after launch phase | Show paywall sheet |
FORBIDDEN | 403 | Authenticated but not allowed | Show “no permission” UI |
ONBOARDING_INCOMPLETE | 403 | User must finish onboarding | Redirect to onboarding step |
TENANCY_PENDING | 403 | Tenancy doc awaiting admin approval | Show waiting state |
TENANCY_REJECTED | 403 | Tenancy was rejected | Show re-upload UI |
ACCOUNT_BANNED | 403 | Account banned | Force logout, show ban screen |
ACCOUNT_PENDING_DELETION | 403 | Credentials are correct but the account is soft-deleted and inside the 30-day erasure grace window. Carries meta.deletedAt + meta.deletionScheduledAt. Returned by /auth/login. | Route to the reactivation screen; offer POST /auth/reactivate |
NOT_FOUND | 404 | Resource doesn’t exist | Show empty/missing state |
STATE_CONFLICT | 409 | Resource in wrong state for operation | Refresh data, retry |
ALREADY_HAS_LISTING | 409 | One-listing-per-user uniqueness violated | Use PATCH on existing |
EMAIL_ALREADY_REGISTERED | 409 | Email exists with a different password | Direct user to /login or /forgot-password |
ACCOUNT_EXISTS_VIA_OAUTH | 409 | Email is bound to a social-login identity | Show generic “use your social login” CTA (response does NOT disclose which provider) |
IDEMPOTENCY_KEY_REUSED | 409 | Idempotency-Key already used with different payload | Use a fresh key |
RATE_LIMITED | 429 | Too many requests | Respect Retry-After header |
INTERNAL_ERROR | 500 | Unexpected server failure | Retry once; report requestId |
UPSTREAM_FAILURE | 502 | Dependency failed (Mongo, Redis, etc.) | Retry with backoff |
SERVICE_UNAVAILABLE | 503 | Service temporarily down | Retry with backoff |
STORAGE_NOT_CONFIGURED | 503 | DO Spaces creds not provisioned (dev only) | Surface to ops |
OAUTH_NOT_CONFIGURED | 503 | Firebase creds (FCM_SERVICE_ACCOUNT_JSON + FIREBASE_PROJECT_ID) not provisioned (dev only) | Surface to ops |
MAIL_NOT_CONFIGURED | 503 | Resend creds not provisioned (dev only) | Surface to ops |
PUSH_NOT_CONFIGURED | 503 | FCM/APNs not provisioned (dev only) | Surface to ops |