Error codes#
🔴 Errors mostly arrive with HTTP 200#
The status code is not enough
Data validation, "not found", duplicates and conflicts all return 200 with
success: false. Decide by the response body.
The exception is a malformed request — a parameter of the wrong shape, a forbidden field in a filter. It gets 400 before anything is read or written.
Status codes the API actually uses#
| Code | When |
|---|---|
| 200 | nearly everything, including application errors |
| 204 | CORS preflight, some payment return addresses |
| 400 | a parameter of the wrong shape, a forbidden field in filters, ordering or columns — see Wrong parameter shape |
| 401 | a missing or invalid application key (code 501), or an invalid, expired or revoked user token (code 103) |
| 403 | denied permission |
| 404 | non-existent resource or action — returns HTML |
| 429 | exceeded application, caller, sign-in or token refresh rate limit, with a Retry-After header |
| 500 | unhandled exception — returns HTML |
Result codes#
The number in the code field.
Result codes DO NOT correspond to HTTP statuses
They look similar and do not match. 400 means permission denied, 404 means
rate limit exceeded, 403 means an invalid token.
The common ones#
| Code | Meaning |
|---|---|
0 |
success |
2 |
validation failed — also a wrong parameter shape (then with HTTP 400) |
102 |
user not found; token refresh also returns it for an inactive, blocked or pending-deletion account |
103 |
not signed in |
104 |
account blocked (reported only after a correct password) |
106 |
session expired |
108 |
invalid password — also a missing or wrong current password on a password change |
109 |
account inactive (reported only after a correct password) |
110 |
wrong credentials — the same code for an unknown account and a wrong password |
400 |
permission denied |
501 |
no valid application key (HTTP 401) — API_UNAUTHORIZED |
402 |
access token expired |
403 |
access token invalid |
404 |
rate limit exceeded |
602 |
missing required field |
604 |
a field value cannot be converted to the field's type — the message names the field |
607 |
operation not permitted |
611 |
invalid length — e.g. a new password shorter than 8 characters |
615 |
value not acceptable — e.g. a value on the blacklist or a category not allowed, see Refusal reason |
616 |
item not found |
Account, passwords and e-mail links#
| Code | Meaning |
|---|---|
111 |
the activation link is invalid, used or expired (one code, also for an unknown e-mail) |
112 |
the password reset link is invalid, used or expired (one code, also for an unknown e-mail) |
113 |
sign-in via a third-party service: the e-mail belongs to another account and the service did not verify it — sign in with a password |
114 |
sign-in via a third-party service: the new account was created inactive and waits for activation from the e-mail |
115 |
sign-in via a third-party service: linking to an existing account must be confirmed by a link sent by e-mail |
116 |
the link confirming the linking is invalid, used or expired |
117 |
the account is pending deletion — sign-in is refused, data carries scheduledAt (the deletion date) |
118 |
the link confirming or cancelling the account deletion is invalid, used or expired |
119 |
a deletion request of an account without a password is confirmed by a link sent by e-mail |
120 |
the account was deleted and anonymized — it cannot be saved or changed |
Codes 113–119 arise mostly on the website
Sign-in via a third-party service and account deletion run on the website and have no
HTTP wrapper. Through the API you will mostly meet 117 (sign-in of an account pending
deletion) and 120 (a write to a deleted account).
Ranges#
| Range | Area |
|---|---|
| 100–120 | user, sign-in and account |
| 200–207 | images and files |
| 300–304 | database |
| 400–404 | permissions and tokens |
| 500–504 | API calls |
| 600–626 | data and operations |
| 700–703 | tasks |
| 800–804 | request processing |
Refusal reason (data.errorCode)#
A failed save refused by a business rule carries a single key in data: errorCode —
a stable name of the reason. The result code (code) gives the group, errorCode the exact
cause. The HTTP status is 200.
code |
errorCode |
When |
|---|---|---|
2 |
parameterTooLong |
an advert or profile parameter value is longer than the parameter allows (for an editor, the visible text counts) |
2 |
parameterUrlNotAllowed |
a parameter value contains a link and the parameter forbids links |
2 |
parameterBlacklistedWord |
a parameter value contains an active forbidden word in the language of the request page |
2 |
parameterRequired |
a required parameter is missing — required is evaluated by the parameter rules (e.g. price type) |
2 |
parameterOptionNotAllowed |
the chosen option of a choice parameter is not offered given the other submitted values |
2 |
userTypeDataMissing |
the account type requires a company ID and company name, or a VAT ID, and it is missing |
2 |
currencyRequired, currencyNotAllowed |
a reply price without a currency, or a currency that is not allowed |
400 |
commentOnlyForLoggedIn |
a comment without sign-in in a thread where only signed-in users may comment |
607 |
commentsClosed |
a comment in a thread with comments switched off |
607 |
advertSold |
a reply to a sold advert |
615 |
blacklisted |
the e-mail, phone or IP address is on the site blacklist |
615 |
advertCategoryNotAllowed |
the advert or profile category is disabled or administrator-only |
Details are only in the message text
The response carries no parameter id, no list of missing fields and no type of the blocked
value — only errorCode. The message mentions them (parameter #12, regId, companyName),
but its wording may change. Decide by code and errorCode.
extend-expiration in a paid category returns only the code
The advert/extend-expiration action (adverts and companies) refuses a non-privileged
caller an extension in a paid category with code: 607 and data: null — the reason
(paymentRequired) is only in the message text. An extension in a paid category is paid on
the website.
The administrator is not checked
The rules apply to a non-privileged caller (guest, signed-in user, owner). An application
acting with the admin role bypasses them just like the site administration.
Examples#
No valid application key (HTTP 401) — the same response for a missing, wrong, disabled or revoked key:
{"success":false,"message":"A valid application key (X-API-Key) is required.","data":null,"code":501}
Invalid user token (HTTP 401, the token is invalid, expired or revoked):
Denied (HTTP 403):
Application or caller limit (HTTP 429, header Retry-After: 3):
Sign-in or token refresh limit (HTTP 429, header Retry-After: 240) — the same keys, only
the message also carries the number of seconds:
Wait Retry-After seconds. Decide by code and data.retryAfter, not by the message text.
Missing data (HTTP 200):
That example has no data key
The envelope is not consistent. Read each key defensively.
A value that cannot be converted (HTTP 200):
{"success":false,"code":604,"message":"Invalid value for field \"currencyId\": expected int, got \"1.9\"."}
Too many new records (HTTP 200, no Retry-After):
Returned by saving new content over the content creation quota.
Masked technical error (errorRef)#
A technical failure (database, files, external service, queue, unknown error) reveals nothing about the system's internals in the response. Instead of the exception text you get a generic message and a reference code:
{"success":false,"code":300,"message":"An internal error occurred. Quote the reference when contacting support.","errorRef":"3f9a1c07","data":null}
Pass the errorRef code on to the site administrator — the server log has the full
detail under [errorRef=3f9a1c07]. The client does not act on the message text; code
decides. Domain errors (validation, state, not found) have no errorRef and their
message does not change.
Wrong parameter shape#
A parameter whose shape differs from what the action expects is not cast — the request
ends with HTTP 400 and code 2, before anything is read or written:
| Example | Why it fails |
|---|---|
filters=x, orderBys=x, columns=x |
text instead of an array |
data=x, meta=x, skipFields=x on save |
text instead of an array |
ids on update-columns missing, empty or text; values is text |
the ID list and the values must be arrays |
ids on register-event is not a non-empty list of positive integers |
1.9, 0 and an empty list do not pass |
computeTotalCount=yes |
a boolean is only 1/0, true/false, on/off |
includes[0][]=user, includes= |
includes is one path or a list of paths |
includes=* or columns[]=… on get-all |
not supported on a listing |
| a filter with an unknown type, without a field, or with a malformed nested group | the filter cannot be built |
the filter option inclusive or isNull sent in the URL |
a boolean is expected, the URL carries only text |
A forbidden field in a filter has its own message
A filter, ordering or column over a field the caller may not read (a password, an IP
address, another user's e-mail, a non-existent field) also returns HTTP 400 and code 2,
with the message Field path "user.email" is not allowed in filters, orderBys or columns.
See Permissions.
400 is a client error — retrying will not help
Fix how the request is built. The message says which parameter is wrong.