Saltar al contenido principal

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

EntornoBase URLCuándo
Producciónhttps://api.neuroon.aiTráfico real, datos persistentes, conversiones que cuentan
Desarrollohttps://dev-api.neuroon.aiPruebas 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. camelCase en todos los campos.
  • Response body: JSON camelCase. Las claves siempre son strings; los números pueden ser int, long, decimal (precios). Las fechas son ISO 8601 (2026-05-06T10:15:00Z o sin Z si 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

HeaderAplica aValor
Content-Typerequests con bodyapplication/json
Acceptrecomendadoapplication/json
Authorization o X-Widget-Token o X-Shop-API-Keysegún endpointVer 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 a es.
  • User-Agent: TuApp/1.2.3 — para tu propio análisis en logs (recomendado).

Idempotencia

  • POST /api/plugin/shops/{shopId}/products/sync es idempotente por externalId: enviar el mismo externalId dos veces actualiza el producto, no duplica. Esto incluye el modo INCREMENTAL (por defecto). El modo FULL borra el catálogo completo en Neuroon antes de reinsertar — úsalo solo en migraciones iniciales.
  • POST /api/plugin/shops/{shopId}/track/conversion acepta orderId único por shop; un segundo POST con el mismo orderId se ignora silenciosamente (no duplica métricas).
  • POST /api/widget/track/click y POST /api/widget/track/conversion se identifican por searchLogId + 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 OK en products/sync. El producto no es buscable inmediatamente. Si tu test de integración hace GET /products/{externalId} justo después del sync, espera ~5 s o pollea con backoff.
  • Cuotas: productsCount y searchesThisMonth en GET /shops/me se 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) — WidgetRateLimitFilter emite { error, message, retryAfter, limit, remaining, timestamp }. Sin status ni path.
  • 401 / 403 desde filtros de authApiKeyAuthenticationFilter emite { 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:

EndpointLímite
widget-search200 req/min
widget-suggestions300 req/min
widget-analytics500 req/min
widget-compare10 req/min
sync (plugin)100 req/min
shop-info60 req/min
verification20 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, default 0).
  • size (default 20, máximo 100).
  • sort (formato field,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 header X-Widget-Token cuyo Origin se valida contra app.widget.allowed-origins y shop.url.
  • /api/plugin/*: CORS deshabilitado por diseño — son llamadas server-to-server. Si llamas desde un navegador y tu Origin no coincide con shop.url, recibes 403.
  • /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