Felo APIs
Chat API
Integra la ricerca conversazionale basata su IA con analisi delle query, risorse web e citazioni.
/v2/chatAutenticazione
Bearer API key
Tipo di contenuto
application/json
Note sui limiti
Per API key and per user windows. Read X-RateLimit headers.
La Chat API ti permette di integrare la ricerca conversazionale basata sull'IA nelle tue applicazioni. Invia una query in linguaggio naturale e ricevi una risposta intelligente generata da risultati di ricerca web in tempo reale.
Per i rate limit, le risposte di errore e il comportamento di retry, vedi Errori, limiti e retry.
Panoramica
La Chat API esegue le seguenti operazioni:
- Analizza e ottimizza la tua query
- Cerca sul web informazioni pertinenti
- Classifica e filtra i risultati della ricerca
- Genera una risposta IA completa basata sulle fonti
- Restituisce la risposta con le citazioni delle fonti
Casi d'uso:
- Assistenti IA conversazionali
- Strumenti di ricerca e recupero di informazioni
- Chatbot per l'assistenza clienti con conoscenza del web
- Applicazioni didattiche
- Strumenti di creazione di contenuti
Autenticazione
Tutte le richieste alla Chat API richiedono l'autenticazione tramite una chiave API. Includi la tua chiave API nell'header Authorization:
Authorization: Bearer YOUR_API_KEYVedi la guida all'autenticazione per i dettagli su come ottenere e usare la chiave API.
Uso con agenti IA
Installa il pacchetto completo felo-ai quando vuoi che un agente usi Search e ogni altra Felo Skill disponibile. L'installer individua dinamicamente ogni directory del pacchetto che contiene SKILL.md, quindi include anche le Skill future invece di un sottoinsieme fisso. Installale nella directory nativa del tuo agente: Codex usa ~/.codex/skills, Claude Code usa ~/.claude/skills, OpenClaw usa ~/.agents/skills e Hermes Agent usa ~/.hermes/skills. Vedi la guida alla configurazione manuale degli agenti IA per i passaggi sicuri di link, chiave API e verifica su ogni piattaforma.
Endpoint
POST https://openapi.felo.ai/v2/chatRichiesta
Header
| Header | Obbligatorio | Descrizione |
|---|---|---|
Authorization | Sì | La tua chiave API nel formato: Bearer YOUR_API_KEY |
Content-Type | Sì | Deve essere application/json |
Parametri del corpo
| Parametro | Tipo | Obbligatorio | Descrizione | Vincoli |
|---|---|---|---|---|
query | string | Sì | La domanda o la query di ricerca dell'utente | Da 1 a 2000 caratteri |
Richiesta di esempio
{
"query": "What are the latest developments in quantum computing?"
}Risposta
Risposta di successo (200 OK)
Quando la richiesta riesce, l'API restituisce una risposta JSON con la seguente struttura:
{
"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..."
}
]
}
}Campi della risposta
| Campo | Tipo | Descrizione |
|---|---|---|
status | string | number | Stato della risposta: "ok" in caso di successo; le risposte di errore usano il codice di stato HTTP come numero |
message | string | null | Messaggio aggiuntivo (null per le richieste riuscite) |
data | object | Dati della risposta (presenti solo quando lo stato è "ok") |
data.id | string | Identificatore univoco di questa sessione di chat |
data.message_id | string | Identificatore univoco di questo specifico messaggio |
data.answer | string | Risposta generata dall'IA alla query |
data.query_analysis | object | Analisi della query dell'utente |
data.query_analysis.queries | string[] | Query di ricerca ottimizzate derivate dall'input dell'utente |
data.resources | array | Elenco delle fonti web usate per generare la risposta |
data.resources[].link | string | URL della fonte |
data.resources[].title | string | Titolo della pagina di origine |
data.resources[].snippet | string | Estratto pertinente della fonte |
Risposta di errore
Quando si verifica un errore, l'API restituisce la struttura di errore condivisa:
{
"status": 401,
"code": "UNAUTHORIZED",
"message": "API Key is required",
"request_id": "..."
}Campi della risposta di errore
| Campo | Tipo | Descrizione |
|---|---|---|
status | number | Codice di stato HTTP; le risposte di successo usano "ok" |
code | string | Codice di errore che identifica il tipo di errore |
message | string | Descrizione dell'errore leggibile da una persona |
request_id | string | Identificatore univoco di questa richiesta (utile per il supporto) |
Codici di errore
| HTTP | Codice | Significato |
|---|---|---|
| 400 | Codice di convalida dell'endpoint | Un campo query manca, è vuoto o è troppo lungo; leggi message per il problema specifico |
| 401 | UNAUTHORIZED | La chiave API manca, non è valida o è revocata |
| 429 | RATE_LIMITED | È stato superato un rate limit |
| 502 | CHAT_FAILED | Errore interno del servizio |
| 503 | SERVICE_UNAVAILABLE | Servizio temporaneamente non disponibile |
Per la struttura condivisa, gli altri codici di errore e le regole di retry, vedi Errori, limiti e retry.
Esempi
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?"
}'Risposta:
{
"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 (Browser/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)
}
}Rate limiting
Gli utenti con un abbonamento Felo a pagamento attivo (compresi gli abbonamenti enterprise) sono esenti da tutti i rate limit di /v2/chat, sia per l'autenticazione con chiave API sia per OAuth. Le risposte esenti non includono header X-RateLimit-*.
Gli utenti senza abbonamento a pagamento sono soggetti a rate limit su tre dimensioni. Se lo stato dell'abbonamento non può essere verificato, questi limiti si applicano comunque:
- Per chiave API - limita le richieste effettuate con una singola chiave API entro una finestra di 1 minuto.
- Per utente (minuto) - limita le richieste complessive di tutte le chiavi API di proprietà di un utente entro una finestra di 1 minuto.
- Per utente (ora) - limita le richieste complessive di tutte le chiavi API di proprietà di un utente entro una finestra di 1 ora.
Il superamento di qualsiasi dimensione genera una risposta 429 Too Many Requests.
I limiti numerici esatti possono cambiare nel tempo. Leggili sempre dagli header di risposta riportati sotto, non dagli snapshot della documentazione.
Header di risposta (risposte soggette a rate limit, comprese le 429):
| Header | Significato |
|---|---|
X-RateLimit-Limit | Limite della dimensione più restrittiva attualmente in vigore |
X-RateLimit-Remaining | Quota rimanente minima tra le tre dimensioni |
X-RateLimit-Reset | Timestamp Unix (secondi) del reset della finestra corrente |
In caso di 429, in aggiunta:
| Header | Significato |
|---|---|
Retry-After | Ritardo di retry consigliato (secondi) |
Corpo di esempio di una 429 (il message riflette i limiti configurati al momento della richiesta):
{
"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": "..."
}Comportamento del client: quando presenti, leggi X-RateLimit-Remaining e riduci proattivamente il ritmo. In caso di 429, attendi almeno Retry-After secondi (o fino a X-RateLimit-Reset) prima di riprovare. Non inserire nel codice valori di limite fissi.
Per la politica di retry completa e le indicazioni sul backoff, vedi Errori, limiti e retry. Se ti servono rate limit più alti, contatta [email protected].
Buone pratiche
1. Gestire gli errori con attenzione
Controlla sempre lo stato della risposta e gestisci gli errori in modo appropriato:
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. Implementare la logica di retry
Per gli errori transitori (codici di stato 5xx), implementa il backoff esponenziale:
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 backoff3. Memorizzare le risposte in cache
Valuta la cache delle risposte per query identiche, per ridurre le chiamate API e migliorare i tempi di risposta.
4. Convalidare l'input
Convalida l'input dell'utente prima di inviarlo all'API:
- Verifica che la query non sia vuota
- Controlla la lunghezza della query (da 1 a 2000 caratteri)
- Sanifica l'input per prevenire attacchi di injection
5. Monitorare l'utilizzo
Tieni traccia dell'utilizzo dell'API per restare entro i rate limit e ottimizzare i costi:
- Registra il numero di richieste e i tempi di risposta
- Monitora i tassi di errore
- Imposta avvisi per comportamenti anomali
Supporto
Serve aiuto con la Chat API?
- Consulta la guida per iniziare
- Leggi la documentazione sull'autenticazione
- Contatta il supporto all'indirizzo [email protected] indicando il tuo request ID
Changelog
v2.0.0 (attuale)
- Rilascio iniziale della Chat API
- Supporto per query in linguaggio naturale
- Integrazione della ricerca web in tempo reale
- Risposte generate dall'IA con citazioni delle fonti