Convenciones de la API
Esta página resume las reglas comunes a todos los endpoints. Si tu integración no respeta estas convenciones, recibirás 400 Bad Request, 401 Unauthorized, o el típico {"timestamp":..., "status":..., "error":..., "message":..., "path":...}.
Base URLs
| Entorno | Base URL | Cuándo |
|---|---|---|
| Producción | https://api.neuroon.ai | Tráfico real, datos persistentes, conversiones que cuentan |
| Desarrollo | https://dev-api.neuroon.ai | Pruebas de integración, payloads de error, edge cases sin riesgo |
Sin versionado en URL — no existe /v1/ ni /v2/. Cambios breaking se anuncian con antelación en el Changelog y se aplican primero a Desarrollo.
Las claves sk_* y los Widget Tokens emitidos en Desarrollo no funcionan contra Producción y viceversa. Usa variables de entorno separadas:
NEUROON_API_URL=https://dev-api.neuroon.ai
NEUROON_API_KEY=sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEUROON_SHOP_ID=shop_dev_xxxxxxxx
Ver Cambiar de entorno para configuración por stack.
Formato
- Request body: JSON con
Content-Type: application/json; charset=utf-8.camelCaseen todos los campos. - Response body: JSON
camelCase. Las claves siempre son strings; los números pueden serint,long,decimal(precios). Las fechas son ISO 8601 (2026-05-06T10:15:00Zo sinZsi es local — el backend devuelve UTC sin offset). - Charset: UTF-8. Spring decodifica el body con UTF-8 — bytes que no sean UTF-8 válidos rompen el parser JSON con
400.
Headers obligatorios
| Header | Aplica a | Valor |
|---|---|---|
Content-Type | requests con body | application/json |
Accept | recomendado | application/json |
Authorization o X-Widget-Token o X-Shop-API-Key | según endpoint | Ver Authentication · Visión general |
Headers opcionales útiles:
Accept-Language: es-ES,en-US,fr-FR, etc. — el backend usa este valor para textos generados (filtros guiados, AI assistant) si encaja con uno de los 9 idiomas soportados; si no, cae aes.User-Agent: TuApp/1.2.3— para tu propio análisis en logs (recomendado).
Idempotencia
POST /api/plugin/shops/{shopId}/products/synces idempotente porexternalId: enviar el mismoexternalIddos veces actualiza el producto, no duplica. Esto incluye el modoINCREMENTAL(por defecto). El modoFULLborra el catálogo completo en Neuroon antes de reinsertar — úsalo solo en migraciones iniciales.POST /api/plugin/shops/{shopId}/track/conversionaceptaorderIdúnico por shop; un segundo POST con el mismoorderIdse ignora silenciosamente (no duplica métricas).POST /api/widget/track/clickyPOST /api/widget/track/conversionse identifican porsearchLogId + productId + timestamp; reintentos seguros.- Los demás endpoints son
GET(sin efectos) o stateless.
Latencia y consistencia
- Indexación de productos: 2-5 segundos tras
200 OKenproducts/sync. El producto no es buscable inmediatamente. Si tu test de integración haceGET /products/{externalId}justo después del sync, espera ~5 s o pollea con backoff. - Cuotas:
productsCountysearchesThisMonthenGET /shops/mese cachean ~5 min en algunos consumidores (plugin WordPress, por ejemplo). El backend siempre devuelve el dato actualizado. - Tokens: el Widget Token tiene TTL de 24 h (86400 s). Cachéalo en tu servidor con margen de 5 min antes de la expiración.
Estructura de error
La envoltura estándar la emite GlobalExceptionHandler para casi todos los errores:
{
"timestamp": "2026-05-06T10:15:00",
"status": 400,
"error": "Bad Request",
"message": "externalId: must not be blank, price: must be greater than or equal to 0.0",
"path": "/api/plugin/shops/shop_abc/products/sync"
}
status: HTTP code numérico.error: nombre canónico del status.message: errores field-level concatenados con coma; legible para humanos.path: ruta de la petición (sin host).
Casos especiales con envoltura distinta:
429(rate limit) —WidgetRateLimitFilteremite{ error, message, retryAfter, limit, remaining, timestamp }. Sinstatusnipath.401/403desde filtros de auth —ApiKeyAuthenticationFilteremite{ error, status }sin pasar por el handler global.
Detalle por código en Reference · Errores.
Rate limits
Throttling por endpoint, no por plan de subscripción:
| Endpoint | Límite |
|---|---|
widget-search | 200 req/min |
widget-suggestions | 300 req/min |
widget-analytics | 500 req/min |
widget-compare | 10 req/min |
sync (plugin) | 100 req/min |
shop-info | 60 req/min |
verification | 20 req/min |
Headers de respuesta: X-RateLimit-Limit, X-RateLimit-Remaining. En 429, también Retry-After (segundos).
Detalle y backoff exponencial en Rate limits.
Paginación
GET /api/plugin/shops/{shopId}/products y endpoints derivados aceptan:
page(0-indexed, default0).size(default20, máximo100).sort(formatofield,direction, ej.name,asc).modifiedAfter(ISO 8601, para delta sync incremental).
Respuesta paginada:
{
"content": [...],
"page": 0,
"size": 20,
"totalElements": 1247,
"totalPages": 63,
"first": true,
"last": false
}
CORS
/api/widget/*: CORS abierto a cualquier origen (es JS desde navegadores de clientes); credenciales por headerX-Widget-TokencuyoOriginse valida contraapp.widget.allowed-originsyshop.url./api/plugin/*: CORS deshabilitado por diseño — son llamadas server-to-server. Si llamas desde un navegador y tu Origin no coincide conshop.url, recibes403./api/search/*: CORS configurado para el dashboard y subdominios*.neuroon.ai.
Si tu integración server-to-server pasa por un proxy que añade Origin automáticamente y rompe la validación, configura el proxy para no enviar el header.
Próximas lecturas
- Authentication · Visión general — qué credencial usar.
- Rate limits — tabla completa y backoff.
- Reference · Errores — todos los códigos.
- Reference · Modelos de datos — schemas reales.