Reference · Errors
This page lists the HTTP codes the Neuroon API can return and the common body shape. All error responses come from el backend except for specific cases.
Body shape
{
"timestamp": "2026-05-06T10:15:00",
"status": 400,
"error": "Bad Request",
"message": "field-level error joined with commas",
"path": "/api/widget/search"
}
| Field | Type | Notes |
|---|---|---|
timestamp | string | LocalDateTime.now.toString — no explicit timezone (server in UTC). |
status | number | HTTP code. |
error | string | Reason phrase of the status (Bad Request, Unauthorized, …). |
message | string | Detail. On 400, validation errors are concatenated with , . |
path | string | Path without the uri= prefix added by WebRequest. |
HTTP codes
| Status | Typical cause | How to fix |
|---|---|---|
| 400 Bad Request | Failed validation (@Valid, missing @RequestParam, IllegalArgumentException, IllegalStateException). | Inspect the field names in message and re-send. |
| 401 Unauthorized | credenciales inválidas or missing/invalid token. The expected header is X-Widget-Token or X-Shop-API-Key depending on the endpoint. | Check the header; refresh the token if it expired. |
| 403 Forbidden | permiso denegado: Widget Token origin mismatch or cross-tenant on plugin endpoints. | Verify the token belongs to the requested shopId and the Origin domain is allowed. |
| 404 Not Found | Resource doesn't exist (shopId, product, plan). | Check the id; on product sync, verify the shop exists first. |
| 409 Conflict | Identity duplicate (e.g. externalId already registered in full sync). | Consider whether it should be INCREMENTAL instead of FULL. |
| 422 Unprocessable Entity | Business rules: parent product not found, currency mismatch between items, etc. | Inspect message; fix the payload. |
| 429 Too Many Requests | Rate limit exceeded. | Wait the time stated in Retry-After and retry with jitter. See Rate Limits. |
| 500 Internal Server Error | Uncaught exception (generic Exception). | Report to support with timestamp and path. |
| 502 Bad Gateway | An external provider this route depends on failed. | Retry with backoff; if it persists, contact support. |
| 503 Service Unavailable | Circuit breaker open on an external provider. | Wait and retry with backoff. |
Domain-specific errors
These are not new HTTP statuses: they travel inside message with the same generic body, but it's useful to recognize them because your integration usually wants to handle them differently.
| Message (key) | Status | Meaning |
|---|---|---|
DUPLICATE_EXTERNAL_ID | 409 | The externalId already exists on FULL sync. Switch to INCREMENTAL or wipe the shop. |
PARENT_PRODUCT_NOT_FOUND | 422 | You are syncing a variant whose parentProductId doesn't exist. Sync the parent first. |
SHOP_NOT_FOUND | 404 | The path's shopId doesn't exist. |
WIDGET_TOKEN_EXPIRED | 401 | The token has expired (TTL 24 h). Regenerate and re-render. |
ORIGIN_NOT_ALLOWED | 403 | The Origin header doesn't match the authorized domains. Add it from the Dashboard. |
RATE_LIMIT_EXCEEDED | 429 | Quota exceeded. See Retry-After and X-RateLimit-*. |
If your platform needs stable error codes as a contract, contact support to enable the extended
{ "code": "...", ... }format. The current default is plain text.
Validation errors (400)
errores de validación and errores de validación are concatenated in message with the format field: description:
{
"timestamp": "2026-05-06T10:15:00",
"status": 400,
"error": "Bad Request",
"message": "products[0].externalId: must not be blank, products[0].price: must be positive",
"path": "/api/plugin/shops/123/products/sync"
}
.
Best practices
- Don't regex-parse
message— the format may change. Usestatusand, if you need semantics, the domain code. - Retry on 429, 502, 503 with exponential backoff + jitter.
- Don't retry on 400, 401, 403, 404, 409, 422 — those are client errors.
- Log
timestampandpathto correlate with the server side when you open a ticket.