Error Responses
All API error responses return a JSON object with a message field and the application/json content type.
Response Structure
Every error response contains:
| Field | Type | Description |
|---|---|---|
message | string | A human-readable explanation of the error. |
Additional Fields
Depending on the error type, extra fields may be present:
| Field | Type | When Present |
|---|---|---|
errors | object | Validation errors (422). Keys are field names, values are arrays of error messages. |
Production Masking
Two kinds of message exist:
- Domain messages — the specific texts documented on the endpoint pages (e.g.
Na tento posudok už máte aktívnu ponuku.,Heslo sa nepodarilo obnoviť.,Unauthenticated., validation messages). They are returned verbatim in every environment and are localized throughAPP_LOCALE— production runs in Slovak, so the texts on this and the endpoint pages are what the API actually sends. The framework mask texts below are not localized. - Framework HTTP errors (
403,404,405,429, unexpected500) — in production the message is replaced by the generic status text:Forbidden,Not Found,Method Not Allowed,Too Many Requests,An unexpected error occurred.. The more specific texts shown for these codes below and on endpoint pages (This action is unauthorized.,Access denied for authenticated users.,Testimony file not found., …) only appear in non-production environments. Branch on the status code, not on the message.
Examples
401 Unauthorized
Returned when authentication is missing or invalid.
{
"message": "Unauthenticated."
}403 Forbidden
Returned when the authenticated user is not authorized for the action: wrong role, not the owner of the resource, a guest-only endpoint called with a token (Access denied for authenticated users.), or an endpoint that requires a verified email called by an unverified user (Access denied for unverified users.).
{
"message": "This action is unauthorized."
}404 Not Found
Returned when the requested resource does not exist.
{
"message": "The requested resource was not found."
}409 Conflict
Returned when the action conflicts with the current resource state — an invalid state transition, a duplicate offer, or an offer that is no longer available.
{
"message": "Prechod zo stavu [completed] do stavu [accepted] nie je možný."
}Every state-changing endpoint (create offer, accept offer, cancel, complete) can also answer 409 when another request modified the same testimony at the same moment. Re-fetch the resource and retry if the action still applies:
{
"message": "Záznam bol medzitým zmenený. Skúste to znova."
}422 Unprocessable Content
Returned when validation fails. Includes an errors object with per-field messages.
{
"message": "E-mail musí byť platná emailová adresa. (a 2 ďalších chýb)",
"errors": {
"email": [
"E-mail musí byť platná emailová adresa."
],
"password": [
"Heslo musí mať minimálne 8 znakov.",
"Musíte potvrdiť Heslo."
]
}
}429 Too Many Requests
Returned when a rate limit is exceeded. The Retry-After header tells how many seconds to wait; X-RateLimit-Limit and X-RateLimit-Remaining are sent on every rate-limited endpoint.
{
"message": "Too Many Attempts."
}| Endpoints | Limit |
|---|---|
| Login, Register Client, Register Expert, Send Password Reset Email, Password Reset | 5 requests per minute per IP address |
| Check Email | 10 requests per minute per IP address |
| Resend Verification Email | 3 requests per minute per user (or IP) |
All authenticated endpoints (/me/*, testimonies, offers, sandbox) | 120 requests per minute per user |
| Checkout Offer | additionally 3 requests per minute per user |
500 Internal Server Error
Returned when an unexpected server error occurs. The message is masked in production.
Production:
{
"message": "An unexpected error occurred."
}Non-production (includes the actual exception message):
{
"message": "SQLSTATE[42S02]: Base table or view not found..."
}Content Type
All error responses are returned with the header:
Content-Type: application/json