Felo API PlatformFelo API Platform

Felo APIs

Chat API

Integra búsqueda conversacional con IA, con análisis de consultas, recursos web y citas.

POST/v2/chat

Autenticación

Bearer API key

Tipo de contenido

application/json

Notas sobre límites

Per API key and per user windows. Read X-RateLimit headers.

La Chat API te permite integrar búsqueda conversacional impulsada por IA en tus aplicaciones. Envía una consulta en lenguaje natural y recibe una respuesta inteligente generada a partir de resultados de búsqueda web en tiempo real.

Para conocer los límites de solicitudes, las respuestas de error y el comportamiento de reintento, consulta Errores, límites y reintentos.

Descripción general

La Chat API realiza las siguientes operaciones:

  1. Analiza y optimiza tu consulta
  2. Busca en la web información relevante
  3. Clasifica y filtra los resultados de búsqueda
  4. Genera una respuesta completa de IA basada en las fuentes
  5. Devuelve la respuesta junto con las citas de las fuentes

Casos de uso:

  • Asistentes de IA conversacionales
  • Herramientas de investigación y recuperación de información
  • Chatbots de atención al cliente con conocimiento web
  • Aplicaciones educativas
  • Herramientas de creación de contenido

Autenticación

Todas las solicitudes a la Chat API requieren autenticación mediante una clave de API. Incluye tu clave de API en el encabezado Authorization:

Authorization: Bearer YOUR_API_KEY

Consulta la guía de autenticación para obtener detalles sobre cómo obtener y usar tu clave de API.

Uso con agentes de IA

Instala el paquete completo felo-ai cuando quieras que un agente use Search y todas las demás Felo Skills disponibles. El instalador descubre dinámicamente todos los directorios del paquete que contengan SKILL.md, por lo que incluye las Skills futuras en lugar de un subconjunto fijo. Instálalas en el directorio nativo de tu agente: Codex usa ~/.codex/skills, Claude Code usa ~/.claude/skills, OpenClaw usa ~/.agents/skills y Hermes Agent usa ~/.hermes/skills. Consulta la guía de configuración manual de agentes de IA para conocer los pasos de enlace seguro, clave de API y verificación de cada plataforma.

Endpoint

POST https://openapi.felo.ai/v2/chat

Solicitud

Encabezados

EncabezadoObligatorioDescripción
AuthorizationSíTu clave de API con el formato: Bearer YOUR_API_KEY
Content-TypeSíDebe ser application/json

Parámetros del cuerpo

ParámetroTipoObligatorioDescripciónRestricciones
querystringSíLa pregunta del usuario o la consulta de búsquedaDe 1 a 2000 caracteres

Solicitud de ejemplo

{
  "query": "What are the latest developments in quantum computing?"
}

Respuesta

Respuesta correcta (200 OK)

Cuando la solicitud se completa correctamente, la API devuelve una respuesta JSON con la siguiente estructura:

{
  "status": "ok",
  "message": null,
  "data": {
    "id": "HabCj883yHLSXc8mWqu4Eq",
    "message_id": "18ea8517-5559-4f48-a355-1f8a79e73b71",
    "answer": "Recent developments in quantum computing include...",
    "query_analysis": {
      "queries": [
        "quantum computing latest developments 2025",
        "quantum computing breakthroughs"
      ]
    },
    "resources": [
      {
        "link": "https://example.com/quantum-news",
        "title": "Latest Quantum Computing Breakthroughs",
        "snippet": "Scientists have achieved a major milestone..."
      },
      {
        "link": "https://example.com/quantum-research",
        "title": "Quantum Computing Research 2025",
        "snippet": "New quantum algorithms show promise..."
      }
    ]
  }
}

Campos de la respuesta

CampoTipoDescripción
statusstring | numberEstado de la respuesta: "ok" en caso de éxito; las respuestas de error usan el código de estado HTTP como número
messagestring | nullMensaje adicional (null en las solicitudes correctas)
dataobjectDatos de la respuesta (solo presentes cuando el estado es "ok")
data.idstringIdentificador único de esta sesión de chat
data.message_idstringIdentificador único de este mensaje concreto
data.answerstringRespuesta generada por IA a la consulta
data.query_analysisobjectAnálisis de la consulta del usuario
data.query_analysis.queriesstring[]Consultas de búsqueda optimizadas derivadas de la entrada del usuario
data.resourcesarrayLista de fuentes web usadas para generar la respuesta
data.resources[].linkstringURL de la fuente
data.resources[].titlestringTítulo de la página de la fuente
data.resources[].snippetstringExtracto relevante de la fuente

Respuesta de error

Cuando se produce un error, la API devuelve el sobre de error compartido:

{
  "status": 401,
  "code": "UNAUTHORIZED",
  "message": "API Key is required",
  "request_id": "..."
}

Campos de la respuesta de error

CampoTipoDescripción
statusnumberCódigo de estado HTTP; las respuestas correctas usan "ok"
codestringCódigo de error que identifica el tipo de error
messagestringDescripción del error legible por personas
request_idstringIdentificador único de esta solicitud (útil para soporte)

Códigos de error

HTTPCódigoSignificado
400Código de validación del endpointFalta el campo query, está vacío o es demasiado largo; lee message para conocer el problema concreto
401UNAUTHORIZEDLa clave de API falta, no es válida o está revocada
429RATE_LIMITEDSe superó un límite de solicitudes
502CHAT_FAILEDError interno del servicio
503SERVICE_UNAVAILABLEServicio temporalmente no disponible

Para consultar el sobre compartido, otros códigos de error y las reglas de reintento, consulta Errores, límites y reintentos.

Ejemplos

cURL

curl -X POST https://openapi.felo.ai/v2/chat \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What are the benefits of renewable energy?"
  }'

Respuesta:

{
  "status": "ok",
  "message": null,
  "data": {
    "id": "HabCj883yHLSXc8mWqu4Eq",
    "message_id": "18ea8517-5559-4f48-a355-1f8a79e73b71",
    "answer": "Renewable energy offers numerous benefits including reduced greenhouse gas emissions, decreased air pollution, energy independence, job creation, and long-term cost savings. Solar, wind, and hydroelectric power are sustainable alternatives to fossil fuels that help combat climate change while providing reliable electricity.",
    "query_analysis": {
      "queries": [
        "renewable energy benefits",
        "advantages of renewable energy sources"
      ]
    },
    "resources": [
      {
        "link": "https://example.com/renewable-benefits",
        "title": "Top Benefits of Renewable Energy",
        "snippet": "Renewable energy sources provide clean, sustainable power..."
      }
    ]
  }
}

Python

import requests
import os

# Get API key from environment variable
api_key = os.environ.get('FELO_API_KEY')

url = 'https://openapi.felo.ai/v2/chat'
headers = {
    'Authorization': f'Bearer {api_key}',
    'Content-Type': 'application/json'
}
data = {
    'query': 'What are the benefits of renewable energy?'
}

try:
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()  # Raise exception for HTTP errors

    result = response.json()

    if result['status'] == 'ok':
        print('Answer:', result['data']['answer'])
        print('\nSources:')
        for resource in result['data']['resources']:
            print(f"- {resource['title']}: {resource['link']}")
    else:
        print(f"Error: {result['code']} - {result['message']}")

except requests.exceptions.RequestException as e:
    print(f'Request failed: {e}')

JavaScript (Node.js)

const fetch = require('node-fetch');

const apiKey = process.env.FELO_API_KEY;
const url = 'https://openapi.felo.ai/v2/chat';

const headers = {
  'Authorization': `Bearer ${apiKey}`,
  'Content-Type': 'application/json'
};

const body = JSON.stringify({
  query: 'What are the benefits of renewable energy?'
});

fetch(url, { method: 'POST', headers, body })
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    if (data.status === 'ok') {
      console.log('Answer:', data.data.answer);
      console.log('\nSources:');
      data.data.resources.forEach(resource => {
        console.log(`- ${resource.title}: ${resource.link}`);
      });
    } else {
      console.error(`Error: ${data.code} - ${data.message}`);
    }
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

JavaScript (navegador / Fetch API)

const apiKey = 'YOUR_API_KEY'; // In production, get this from your backend

fetch('https://openapi.felo.ai/v2/chat', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    query: 'What are the benefits of renewable energy?'
  })
})
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    if (data.status === 'ok') {
      console.log('Answer:', data.data.answer);

      // Display sources
      const sourcesList = data.data.resources.map(resource =>
        `<li><a href="${resource.link}">${resource.title}</a></li>`
      ).join('');

      document.getElementById('answer').innerHTML = data.data.answer;
      document.getElementById('sources').innerHTML = sourcesList;
    } else {
      console.error(`Error: ${data.code} - ${data.message}`);
    }
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

Go

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type ChatRequest struct {
    Query string `json:"query"`
}

type ChatResponse struct {
    Status  string `json:"status"`
    Message string `json:"message,omitempty"`
    Data    struct {
        ID            string `json:"id"`
        MessageID     string `json:"message_id"`
        Answer        string `json:"answer"`
        QueryAnalysis struct {
            Queries []string `json:"queries"`
        } `json:"query_analysis"`
        Resources []struct {
            Link    string `json:"link"`
            Title   string `json:"title"`
            Snippet string `json:"snippet"`
        } `json:"resources"`
    } `json:"data,omitempty"`
    Code      string `json:"code,omitempty"`
    RequestID string `json:"request_id,omitempty"`
}

func main() {
    apiKey := os.Getenv("FELO_API_KEY")
    url := "https://openapi.felo.ai/v2/chat"

    requestBody := ChatRequest{
        Query: "What are the benefits of renewable energy?",
    }

    jsonData, err := json.Marshal(requestBody)
    if err != nil {
        fmt.Printf("Error marshaling request: %v\n", err)
        return
    }

    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
    if err != nil {
        fmt.Printf("Error creating request: %v\n", err)
        return
    }

    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("Error making request: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response: %v\n", err)
        return
    }

    var chatResp ChatResponse
    err = json.Unmarshal(body, &chatResp)
    if err != nil {
        fmt.Printf("Error unmarshaling response: %v\n", err)
        return
    }

    if chatResp.Status == "ok" {
        fmt.Println("Answer:", chatResp.Data.Answer)
        fmt.Println("\nSources:")
        for _, resource := range chatResp.Data.Resources {
            fmt.Printf("- %s: %s\n", resource.Title, resource.Link)
        }
    } else {
        fmt.Printf("Error: %s - %s\n", chatResp.Code, chatResp.Message)
    }
}

Límites de solicitudes

Los usuarios con una suscripción de pago de Felo vigente (incluidas las suscripciones empresariales) están exentos de todos los límites de solicitudes de /v2/chat, tanto para la autenticación con clave de API como con OAuth. Las respuestas exentas no incluyen encabezados X-RateLimit-*.

Los usuarios sin suscripción de pago están sujetos a límites de solicitudes en tres dimensiones. Si no se puede verificar el estado de la suscripción, estos límites siguen aplicándose:

  • Por clave de API: limita las solicitudes realizadas con una sola clave de API dentro de una ventana de 1 minuto.
  • Por usuario (minuto): limita las solicitudes agregadas de todas las claves de API propiedad de un usuario dentro de una ventana de 1 minuto.
  • Por usuario (hora): limita las solicitudes agregadas de todas las claves de API propiedad de un usuario dentro de una ventana de 1 hora.

Superar cualquiera de las dimensiones genera una respuesta 429 Too Many Requests.

Los límites numéricos exactos pueden cambiar con el tiempo. Léelos siempre en los encabezados de respuesta que se indican a continuación, no en instantáneas de la documentación.

Encabezados de respuesta (respuestas sujetas a límites de solicitudes, incluido 429):

EncabezadoSignificado
X-RateLimit-LimitLímite de la dimensión más restrictiva actualmente en vigor
X-RateLimit-RemainingCuota restante mínima entre las tres dimensiones
X-RateLimit-ResetMarca de tiempo Unix (segundos) en la que se restablece la ventana actual

En un 429, además:

EncabezadoSignificado
Retry-AfterRetraso recomendado antes de reintentar (segundos)

Ejemplo de cuerpo 429 (el message refleja los límites configurados en el momento de la solicitud):

{
  "status": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests. Limit: <N>/min per API key, <M>/min per user, <H>/hour per user.",
  "request_id": "..."
}

Comportamiento del cliente: cuando esté presente, lee X-RateLimit-Remaining y reduce el ritmo de forma proactiva. En un 429, espera al menos Retry-After segundos (o hasta X-RateLimit-Reset) antes de reintentar. No codifiques los valores de los límites directamente.

Para consultar la política completa de reintentos y las indicaciones sobre el retroceso exponencial, consulta Errores, límites y reintentos. Si necesitas límites de solicitudes más altos, escribe a [email protected].

Prácticas recomendadas

1. Gestiona los errores con elegancia

Comprueba siempre el estado de la respuesta y gestiona los errores como corresponda:

if result['status'] == 'ok':
    # Process successful response
    answer = result['data']['answer']
else:
    # Handle error
    error_code = result['code']
    error_message = result['message']
    # Log error, show user-friendly message, etc.

2. Implementa lógica de reintentos

Para los errores transitorios (códigos de estado 5xx), implementa retroceso exponencial:

import time

max_retries = 3
retry_delay = 1  # seconds

for attempt in range(max_retries):
    response = requests.post(url, headers=headers, json=data)

    if response.status_code < 500:
        break  # Success or client error, don't retry

    if attempt < max_retries - 1:
        time.sleep(retry_delay * (2 ** attempt))  # Exponential backoff

3. Almacena en caché las respuestas

Considera almacenar en caché las respuestas de consultas idénticas para reducir las llamadas a la API y mejorar los tiempos de respuesta.

4. Valida la entrada

Valida la entrada del usuario antes de enviarla a la API:

  • Asegúrate de que la consulta no esté vacía
  • Comprueba la longitud de la consulta (de 1 a 2000 caracteres)
  • Sanea la entrada para evitar ataques de inyección

5. Supervisa el uso

Haz seguimiento del uso de tu API para mantenerte dentro de los límites de solicitudes y optimizar los costes:

  • Registra el número de solicitudes y los tiempos de respuesta
  • Supervisa las tasas de error
  • Configura alertas para patrones inusuales

Soporte

¿Necesitas ayuda con la Chat API?

Registro de cambios

v2.0.0 (actual)

  • Lanzamiento inicial de la Chat API
  • Compatibilidad con consultas en lenguaje natural
  • Integración de búsqueda web en tiempo real
  • Respuestas generadas por IA con citas de las fuentes