Saltar al contenido principal

Límites de uso

Neuroon aplica rate limiting por endpoint, no por plan de subscripción. La cuota por plan (productos sincronizados, búsquedas mensuales) es un concepto separado del throttling de tasa que documenta esta página. Ver Cuotas de plan vs rate limit más abajo.

Estado actual del throttling

Hoy el único filtro activo es WidgetRateLimitFilter (/api/widget/*, autenticado con X-Widget-Token). El filtro RateLimitFilter para la API de plugin existe en código pero su matcher (path.contains("/from-plugin") en RateLimitFilter.java) no coincide con ninguna ruta servida por los controladores actuales — los endpoints reales del plugin son /api/plugin/shops/me, /api/plugin/shops/{shopId}/products/sync, etc., sin el sufijo /from-plugin. Mientras eso siga así, la API de plugin no aplica throttling aunque los buckets estén configurados.

Límites en producción — Widget API

Endpoint internoCoincide conLímiteVentana
widget-search/api/widget/search*2001 min
widget-suggestions/api/widget/suggestions*3001 min
widget-compare/api/widget/.../compare*101 min
widget-analytics/api/widget/.../analytics*5001 min

Valores en RateLimitService.java. Granularidad: por shop (shopId extraído del X-Widget-Token).

Límites configurados — Plugin API (no enforzados todavía)

Estos valores están en código pero el filtro no se activa hoy. Documentados aquí porque seguramente se activarán en una próxima release; planifica con ellos en mente:

Endpoint internoCoincide conLímiteVentana
sync/api/plugin/shops/{shopId}/products/sync1001 min
shop-info/api/plugin/shops/me601 min
verification/api/plugin/shops/{shopId}/verification-data201 min
verify-action (POST)/api/plugin/shops/{shopId}/verify55 min
unverify-action (DELETE)/api/plugin/shops/{shopId}/verify55 min

Headers de respuesta

HeaderCuándo se emiteSignificado
X-RateLimit-LimitToda respuesta de /api/widget/*Cuota total para este endpoint
X-RateLimit-RemainingToda respuesta de /api/widget/*Requests restantes en la ventana actual
Retry-AfterSólo en 429Segundos a esperar antes de reintentar (igual al tamaño de ventana)

Ejemplo de respuesta correcta:

HTTP/1.1 200 OK
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 187
Content-Type: application/json

Cuerpo del error 429

Cuando el bucket se agota, la respuesta es:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
Retry-After: 60
Content-Type: application/json

{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again later.",
"retryAfter": 60,
"limit": 200,
"remaining": 0,
"timestamp": "2026-05-06T10:15:00Z"
}

Backoff exponencial

Reintenta sólo en 429 y 5xx. Respeta Retry-After. Patrón recomendado: 1s, 2s, 4s, 8s con jitter, máximo 3-5 intentos.

import pRetry, { AbortError } from 'p-retry';

async function search(query: string) {
return pRetry(async () => {
  const res = await fetch('https://api.neuroon.ai/api/widget/search', {
    method: 'POST',
    headers: {
      'X-Widget-Token': process.env.NEUROON_WIDGET_TOKEN!,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ query }),
  });
  if (res.status === 429 || res.status >= 500) {
    const retryAfter = Number(res.headers.get('Retry-After')) || 0;
    if (retryAfter > 0) await new Promise(r => setTimeout(r, retryAfter * 1000));
    throw new Error(`Retryable ${res.status}`);
  }
  if (!res.ok) throw new AbortError(`Non-retryable ${res.status}`);
  return res.json();
}, { retries: 3, factor: 2, minTimeout: 1000, randomize: true });
}

Cuotas de plan vs rate limit

Son dos capas distintas. No las confundas:

ConceptoQué controlaDónde se veGranularidad
Rate limit (esta página)Picos por minuto/cinco minutosHeaders X-RateLimit-*, error 429Por endpoint, igual para todos
Cuota de planVolumen total mensual y catálogo máximoGET /api/plugin/shops/memaxProducts, productsCount, maxSearchesPerMonth, searchesThisMonthPor shop, depende del plan

El plan tier (BASIC, GROWTH, PRO, ENTERPRISE) afecta a maxProducts y maxSearchesPerMonth retornados por /shops/me, no a los rate limits por endpoint, que son globales. Si tu integración necesita más volumen mensual, contacta soporte para subir de plan; los rate limits por endpoint no se elevan por plan.

Buenas prácticas

  • Cachea /api/plugin/shops/me unos 5 min en el cliente como hace el plugin WordPress oficial; aunque el filtro de plugin no esté activo, el endpoint es relativamente caro y productsCount/searchesThisMonth cambian lentamente.
  • No abuses de widget-compare (10/min): cachea resultados o agrupa comparaciones.
  • Sincroniza productos en lotes de hasta 500 (BATCH_SIZE del plugin) y espacia las llamadas; el bucket de sync permitirá 100 req/min cuando el filtro se active.
  • No reintentes en 400, 401, 403, 404 ni 422 — son errores deterministas, reintentar no los corrige.
  • Respeta Retry-After estrictamente. Ignorarlo puede llevar a bloqueo manual.

Próximas lecturas

  • Errores — estructura completa del resto de errores 4xx/5xx.
  • Shop API Key — generación, rotación y validación de Origin.
  • Widget Token — TTL 24 h y renovación.