Felo API PlatformFelo API Platform

Felo APIs

Chat API

Intégrez une recherche conversationnelle assistée par IA avec analyse des requêtes, ressources web et citations.

POST/v2/chat

Authentification

Bearer API key

Type de contenu

application/json

Notes sur les limites

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

L'API Chat vous permet d'intégrer une recherche conversationnelle propulsée par l'IA dans vos applications. Envoyez une requête en langage naturel et recevez une réponse intelligente générée à partir de résultats de recherche web en temps réel.

Pour les limites de débit, les réponses d'erreur et le comportement de nouvelle tentative, consultez Erreurs, limites et nouvelles tentatives.

Aperçu

L'API Chat effectue les opérations suivantes :

  1. Elle analyse et optimise votre requête
  2. Elle recherche sur le web les informations pertinentes
  3. Elle classe et filtre les résultats de recherche
  4. Elle génère une réponse IA complète à partir des sources
  5. Elle renvoie la réponse accompagnée des citations des sources

Cas d'usage :

  • Assistants IA conversationnels
  • Outils de recherche et de récupération d'informations
  • Chatbots d'assistance client enrichis par la connaissance du web
  • Applications éducatives
  • Outils de création de contenu

Authentification

Toutes les requêtes à l'API Chat nécessitent une authentification par clé API. Incluez votre clé API dans l'en-tête Authorization :

Authorization: Bearer YOUR_API_KEY

Consultez le guide d'authentification pour les détails sur l'obtention et l'utilisation de votre clé API.

Utilisation avec des agents IA

Installez le paquet complet felo-ai lorsque vous voulez qu'un agent utilise Search et tous les autres Felo Skills disponibles. L'installateur découvre dynamiquement chaque répertoire de paquet contenant SKILL.md, il inclut donc les Skills futurs plutôt qu'un sous-ensemble figé. Installez-les dans le répertoire natif de votre agent : Codex utilise ~/.codex/skills, Claude Code utilise ~/.claude/skills, OpenClaw utilise ~/.agents/skills et Hermes Agent utilise ~/.hermes/skills. Consultez le guide d'installation manuelle des agents IA pour les étapes sûres de création de liens, de clé API et de vérification pour chaque plateforme.

Endpoint

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

Requête

En-têtes

En-têteRequisDescription
AuthorizationOuiVotre clé API au format : Bearer YOUR_API_KEY
Content-TypeOuiDoit être application/json

Paramètres du corps

ParamètreTypeRequisDescriptionContraintes
querystringOuiLa question ou la requête de recherche de l'utilisateur1 à 2000 caractères

Exemple de requête

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

Réponse

Réponse de succès (200 OK)

Lorsque la requête aboutit, l'API renvoie une réponse JSON avec la structure suivante :

{
  "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..."
      }
    ]
  }
}

Champs de réponse

ChampTypeDescription
statusstring | numberStatut de la réponse : "ok" en cas de succès ; les réponses d'erreur utilisent le code de statut HTTP sous forme de nombre
messagestring | nullMessage supplémentaire (null pour les requêtes réussies)
dataobjectDonnées de réponse (présentes uniquement lorsque status vaut "ok")
data.idstringIdentifiant unique de cette session de chat
data.message_idstringIdentifiant unique de ce message spécifique
data.answerstringRéponse générée par l'IA à la requête
data.query_analysisobjectAnalyse de la requête de l'utilisateur
data.query_analysis.queriesstring[]Requêtes de recherche optimisées dérivées de la saisie de l'utilisateur
data.resourcesarrayListe des sources web utilisées pour générer la réponse
data.resources[].linkstringURL de la source
data.resources[].titlestringTitre de la page source
data.resources[].snippetstringExtrait pertinent de la source

Réponse d'erreur

Lorsqu'une erreur se produit, l'API renvoie l'enveloppe d'erreur commune :

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

Champs de réponse d'erreur

ChampTypeDescription
statusnumberCode de statut HTTP ; les réponses de succès utilisent "ok"
codestringCode d'erreur identifiant le type d'erreur
messagestringDescription de l'erreur lisible par un humain
request_idstringIdentifiant unique de cette requête (utile pour le support)

Codes d'erreur

HTTPCodeSignification
400Code de validation de l'endpointUn champ query est manquant, vide ou trop long ; lisez message pour le problème précis
401UNAUTHORIZEDLa clé API est manquante, invalide ou révoquée
429RATE_LIMITEDUne limite de débit a été dépassée
502CHAT_FAILEDErreur interne du service
503SERVICE_UNAVAILABLEService temporairement indisponible

Pour l'enveloppe commune, les autres codes d'erreur et les règles de nouvelle tentative, consultez Erreurs, limites et nouvelles tentatives.

Exemples

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?"
  }'

Réponse :

{
  "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 (navigateur / 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)
    }
}

Limitation de débit

Les utilisateurs disposant d'un abonnement Felo payant effectif (y compris les abonnements entreprise) sont exemptés de toutes les limites de débit de /v2/chat, pour l'authentification par clé API comme par OAuth. Les réponses exemptées n'incluent pas d'en-têtes X-RateLimit-*.

Les utilisateurs sans abonnement payant sont soumis à des limites de débit sur trois dimensions. Si le statut d'abonnement ne peut pas être vérifié, ces limites s'appliquent :

  • Par clé API : limite les requêtes effectuées avec une même clé API dans une fenêtre de 1 minute.
  • Par utilisateur (minute) : limite le total des requêtes de toutes les clés API appartenant à un utilisateur dans une fenêtre de 1 minute.
  • Par utilisateur (heure) : limite le total des requêtes de toutes les clés API appartenant à un utilisateur dans une fenêtre de 1 heure.

Le dépassement de n'importe quelle dimension déclenche une réponse 429 Too Many Requests.

Les limites numériques exactes peuvent évoluer. Lisez-les toujours dans les en-têtes de réponse ci-dessous, et non dans des instantanés de documentation.

En-têtes de réponse (réponses soumises à limitation, y compris 429) :

En-têteSignification
X-RateLimit-LimitLimite de la dimension la plus restrictive actuellement en vigueur
X-RateLimit-RemainingQuota restant minimal sur les trois dimensions
X-RateLimit-ResetHorodatage Unix (secondes) de la réinitialisation de la fenêtre en cours

Sur un 429, en plus :

En-têteSignification
Retry-AfterDélai de nouvelle tentative recommandé (secondes)

Exemple de corps 429 (le message reflète les limites configurées au moment de la requête) :

{
  "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": "..."
}

Comportement du client : lorsqu'il est présent, lisez X-RateLimit-Remaining et réduisez proactivement la cadence. Sur un 429, attendez au moins Retry-After secondes (ou jusqu'à X-RateLimit-Reset) avant de réessayer. Ne codez pas les valeurs de limite en dur.

Pour la politique complète de nouvelle tentative et les conseils de backoff, consultez Erreurs, limites et nouvelles tentatives. Si vous avez besoin de limites de débit plus élevées, contactez [email protected].

Bonnes pratiques

1. Gérer les erreurs proprement

Vérifiez toujours le statut de la réponse et traitez les erreurs comme il se doit :

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. Implémenter une logique de nouvelle tentative

Pour les erreurs transitoires (codes de statut 5xx), implémentez un backoff exponentiel :

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. Mettre les réponses en cache

Envisagez de mettre en cache les réponses aux requêtes identiques pour réduire les appels API et améliorer les temps de réponse.

4. Valider les entrées

Validez la saisie de l'utilisateur avant de l'envoyer à l'API :

  • Assurez-vous que la requête n'est pas vide
  • Vérifiez la longueur de la requête (1 à 2000 caractères)
  • Assainissez l'entrée pour prévenir les attaques par injection

5. Surveiller l'utilisation

Suivez votre utilisation de l'API pour rester dans les limites de débit et optimiser les coûts :

  • Journalisez le nombre de requêtes et les temps de réponse
  • Surveillez les taux d'erreur
  • Configurez des alertes pour les schémas inhabituels

Support

Besoin d'aide avec l'API Chat ?

Journal des modifications

v2.0.0 (actuelle)

  • Version initiale de l'API Chat
  • Prise en charge des requêtes en langage naturel
  • Intégration de la recherche web en temps réel
  • Réponses générées par l'IA avec citations des sources