Integración por API

Referencia de la API de búsqueda de XEYE: endpoint POST /api/v1/search, autenticación con clave API, parámetros, respuesta, errores y límites.

Claves API

Las claves API autentican las llamadas a la API de búsqueda. Créalas desde la página Claves API, etiquétalas según dónde se usan y rótalas creando una nueva y borrando la antigua.

Una clave da acceso a las listas públicas de tu cuenta, y solo a ellas. Las listas privadas se prueban desde la página Búsqueda de la consola (que usa tu sesión, no una clave). Para que una integración pueda consultar una lista, márcala como pública.

Cualquiera con una clave puede buscar en todas tus listas públicas. Guarda las claves en tu servidor: nunca las incluyas en código frontend ni en apps móviles.

El endpoint de búsqueda

La búsqueda es una única llamada HTTP POST con cuerpo JSON, autenticada con la cabecera X-API-Key. Solo sirve listas públicas.

cURL
curl -X POST https://search.xeye.es/api/v1/search \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "list_name": "products",
    "search_term": "wireless headphones",
    "limit": 5
  }'

Cuerpo de la petición

El cuerpo es estricto: un campo desconocido, un término en blanco o un valor fuera de rango responden 422 con el detalle por campo.

  • list_name

    obligatorio Nombre de la lista (pública) donde buscar, exactamente como aparece en la consola (máx. 100 caracteres).

  • search_term

    obligatorio La consulta del usuario (1–500 caracteres, se recortan los espacios). Las erratas y palabras parciales no son problema: la coincidencia es difusa y semántica.

  • limit

    opcional Número máximo de resultados a devolver, de 1 a 1000. Por defecto 50.

  • session

    opcional Identificador libre de la sesión del usuario final (máx. 255). Agrupa sus búsquedas en el historial de la lista y enlaza con /target.

  • include_score_breakdown

    opcional Si es true, cada resultado incluye text_score y semantic_score además de score. Por defecto false.

  • register_log

    opcional Obsoleto e ignorado: toda búsqueda se guarda en el historial de la lista. Se acepta solo para no romper integraciones antiguas.

JavaScript
const response = await fetch('https://search.xeye.es/api/v1/search', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.XEYE_API_KEY,
  },
  body: JSON.stringify({
    list_name: 'products',
    search_term: 'wireless headphones',
    limit: 5,
    session: sessionId,          // optional: groups a user's searches
    include_score_breakdown: true,
  }),
})

const { results } = await response.json()

La respuesta

Los resultados vienen ordenados por puntuación (0–1, cuanto más alta mejor). Cada uno incluye el texto del elemento («item»), sus parámetros intactos y, si lo pediste, el desglose texto/semántica. duration_ms es el tiempo de búsqueda en el servidor.

200 OK
{
  "success": true,
  "results": [
    {
      "item": "Sony WH-1000XM5 wireless headphones",
      "score": 0.93,
      "params": {
        "sku": "SONY-XM5",
        "url": "/products/sony-wh-1000xm5",
        "price": 348
      },
      "text_score": 0.71,
      "semantic_score": 0.96
    }
  ],
  "total_results": 1,
  "search_term": "wireless headphones",
  "list_name": "products",
  "duration_ms": 42,
  "degraded": false,
  "degradation_reasons": []
}

Respuestas degradadas

Toda respuesta lleva degraded y degradation_reasons. Si degraded es true, la búsqueda se ha servido con menos calidad y el motivo lo dice: no_embeddings (la lista no tiene entrenamiento en uso: solo texto), model_unavailable (el modelo de embeddings no pudo cargarse), model_mismatch (los vectores no cuadran con el modelo: reentrena) o stale_data (datos caducos que no se pudieron refrescar). La cabecera X-Search-Degraded: true lo indica también.

Registrar la elección: /target

Opcional. Cuando el usuario final elige un resultado, envía POST /api/v1/target con list_name, target_term (el texto del elemento elegido) y la misma session de la búsqueda. Solo registra la elección en el historial; no busca nada. Responde {"success": true}.

cURL
curl -X POST https://search.xeye.es/api/v1/target \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "list_name": "products",
    "target_term": "Sony WH-1000XM5 wireless headphones",
    "session": "b1f2-…"
  }'

Límites de uso

El cupo de búsquedas por minuto es por cuenta: todas tus claves API (y el playground de la consola) lo comparten. Por defecto son 60 búsquedas/min; un administrador puede fijar otro valor para tu cuenta. Además hay un límite por dirección IP que se aplica antes de validar la clave.

Cada respuesta autenticada incluye X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset (segundos hasta la siguiente ventana). Al agotarse el cupo recibes 429 con Retry-After.

Errores

Todos los errores comparten el mismo cuerpo JSON: status, error (frase HTTP), code (identificador estable para tu código) y message (texto en inglés que puede cambiar); los 422 añaden details con el motivo por campo. Decide por code, no por message.

429
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 23

{
  "status": 429,
  "error": "Too Many Requests",
  "code": "RATE_LIMITED",
  "message": "Rate limit of 60 requests per minute per account exceeded; retry in 23 seconds"
}
HTTPcodeSignificadoQué hacer
400INVALID_HOSTLa cabecera Host no es la del servicio.Llama a la URL pública del servicio de búsqueda, sin proxies que reescriban Host.
401API_KEY_MISSING · API_KEY_INVALIDFalta la cabecera X-API-Key, o la clave no existe o fue revocada.Revisa la clave o crea una nueva.
403LIST_NOT_PUBLICLa lista es privada.Haz la lista pública desde sus ajustes; las privadas solo se prueban desde la consola.
404LIST_NOT_FOUNDNo hay ninguna lista con ese nombre en tu cuenta.Revisa list_name: debe coincidir exactamente con el nombre de la lista.
413REQUEST_TOO_LARGEEl cuerpo de la petición supera el tamaño máximo (16 KB).Envía solo los campos documentados; search_term admite hasta 500 caracteres.
422VALIDATION_FAILEDCuerpo inválido: campo desconocido, término en blanco o valor fuera de rango.Mira details: indica el campo y el motivo.
429RATE_LIMITEDCupo de búsquedas por minuto de tu cuenta (o de tu IP) agotado.Espera los segundos de Retry-After y reintenta; usa X-RateLimit-Remaining para no llegar al límite.
503SERVICE_NOT_READY · BACKEND_UNAVAILABLEEl buscador aún está cargando sus catálogos (SERVICE_NOT_READY) o no pudo cargar los datos de la lista (BACKEND_UNAVAILABLE).Reintenta pasados los segundos de Retry-After; si persiste, consulta la página de estado (/status).

Recomendaciones

  • Llama a la API desde tu backend y guarda la clave en una variable de entorno, no en código cliente.

  • Usa una clave por entorno o integración: así puedes revocar una sin romper el resto.

  • Controla el 429 con un pequeño reintento/backoff respetando Retry-After: el cupo es por cuenta y por minuto.

  • Envía session e informa de la elección con /target: el historial de búsquedas te dirá qué consultas no encuentran lo que esperan tus usuarios.