Felo APIs
Chat API
Integreer AI-gedreven conversationeel zoeken met query-analyse, webbronnen en citaties.
/v2/chatAuthenticatie
Bearer API key
Inhoudstype
application/json
Toelichting op limieten
Per API key and per user windows. Read X-RateLimit headers.
Met de Chat API kun je AI-gedreven conversationeel zoeken in je applicaties integreren. Je stuurt een vraag in natuurlijke taal en ontvangt een intelligent antwoord dat is gegenereerd op basis van realtime zoekresultaten van het web.
Zie Fouten, limieten en nieuwe pogingen voor rate limits, foutresponsen en het gedrag bij nieuwe pogingen.
Overzicht
De Chat API voert de volgende stappen uit:
- Je query analyseren en optimaliseren
- Het web doorzoeken op relevante informatie
- Zoekresultaten rangschikken en filteren
- Een uitgebreid AI-antwoord genereren op basis van de bronnen
- Het antwoord retourneren samen met bronverwijzingen
Gebruiksscenario's:
- Conversationele AI-assistenten
- Tools voor onderzoek en informatieopvraging
- Klantenservicechatbots met webkennis
- Educatieve applicaties
- Tools voor contentcreatie
Authenticatie
Alle verzoeken aan de Chat API vereisen authenticatie met een API-sleutel. Neem je API-sleutel op in de Authorization-header:
Authorization: Bearer YOUR_API_KEYZie de authenticatiehandleiding voor informatie over het verkrijgen en gebruiken van je API-sleutel.
Gebruik met AI-agents
Installeer het volledige pakket felo-ai als je wilt dat een agent Search en alle andere beschikbare Felo Skills gebruikt. Het installatieprogramma ontdekt dynamisch elke pakketmap die SKILL.md bevat, zodat ook toekomstige Skills worden meegenomen in plaats van een vaste subset. Installeer ze in de eigen map van je agent: Codex gebruikt ~/.codex/skills, Claude Code gebruikt ~/.claude/skills, OpenClaw gebruikt ~/.agents/skills en Hermes Agent gebruikt ~/.hermes/skills. Zie de handleiding voor handmatige AI-agentconfiguratie voor de veilige koppeling, de API-sleutel en de verificatiestappen per platform.
Endpoint
POST https://openapi.felo.ai/v2/chatVerzoek
Headers
| Header | Verplicht | Beschrijving |
|---|---|---|
Authorization | Ja | Je API-sleutel in de vorm: Bearer YOUR_API_KEY |
Content-Type | Ja | Moet application/json zijn |
Bodyparameters
| Parameter | Type | Verplicht | Beschrijving | Beperkingen |
|---|---|---|---|---|
query | string | Ja | De vraag of zoekopdracht van de gebruiker | 1-2000 tekens |
Voorbeeldverzoek
{
"query": "What are the latest developments in quantum computing?"
}Respons
Succesrespons (200 OK)
Als het verzoek slaagt, retourneert de API een JSON-respons met de volgende structuur:
{
"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..."
}
]
}
}Responsvelden
| Veld | Type | Beschrijving |
|---|---|---|
status | string | number | Responsstatus: "ok" bij succes; foutresponsen gebruiken de HTTP-statuscode als getal |
message | string | null | Aanvullend bericht (null bij geslaagde verzoeken) |
data | object | Responsgegevens (alleen aanwezig wanneer status "ok" is) |
data.id | string | Unieke identificatie van deze chatsessie |
data.message_id | string | Unieke identificatie van dit specifieke bericht |
data.answer | string | Door AI gegenereerd antwoord op de query |
data.query_analysis | object | Analyse van de query van de gebruiker |
data.query_analysis.queries | string[] | Geoptimaliseerde zoekopdrachten die uit de invoer van de gebruiker zijn afgeleid |
data.resources | array | Lijst met webbronnen die zijn gebruikt om het antwoord te genereren |
data.resources[].link | string | URL van de bron |
data.resources[].title | string | Titel van de bronpagina |
data.resources[].snippet | string | Relevant fragment uit de bron |
Foutrespons
Als er een fout optreedt, retourneert de API het gedeelde foutformaat:
{
"status": 401,
"code": "UNAUTHORIZED",
"message": "API Key is required",
"request_id": "..."
}Velden van de foutrespons
| Veld | Type | Beschrijving |
|---|---|---|
status | number | HTTP-statuscode; succesresponsen gebruiken "ok" |
code | string | Foutcode die het type fout aangeeft |
message | string | Leesbare beschrijving van de fout |
request_id | string | Unieke identificatie van dit verzoek (handig voor support) |
Foutcodes
| HTTP | Code | Betekenis |
|---|---|---|
| 400 | Validatiecode van het endpoint | Een query-veld ontbreekt, is leeg of te lang; lees message voor het specifieke probleem |
| 401 | UNAUTHORIZED | API-sleutel ontbreekt, is ongeldig of ingetrokken |
| 429 | RATE_LIMITED | Een rate limit is overschreden |
| 502 | CHAT_FAILED | Interne fout in de dienst |
| 503 | SERVICE_UNAVAILABLE | Dienst tijdelijk niet beschikbaar |
Zie Fouten, limieten en nieuwe pogingen voor het gedeelde foutformaat, andere foutcodes en de regels voor nieuwe pogingen.
Voorbeelden
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?"
}'Respons:
{
"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 limits
Gebruikers met een actief betaald Felo-abonnement (inclusief enterprise-abonnementen) zijn vrijgesteld van alle rate limits voor /v2/chat, zowel bij authenticatie met een API-sleutel als met OAuth. Vrijgestelde responsen bevatten geen X-RateLimit-*-headers.
Gebruikers zonder betaald abonnement vallen onder rate limits op drie dimensies. Als de abonnementsstatus niet kan worden geverifieerd, blijven deze limieten van toepassing:
- Per API-sleutel - beperkt het aantal verzoeken met één API-sleutel binnen een venster van 1 minuut.
- Per gebruiker (minuut) - beperkt het totale aantal verzoeken over alle API-sleutels van een gebruiker binnen een venster van 1 minuut.
- Per gebruiker (uur) - beperkt het totale aantal verzoeken over alle API-sleutels van een gebruiker binnen een venster van 1 uur.
Als een van de dimensies wordt overschreden, volgt een 429 Too Many Requests-respons.
De exacte numerieke limieten kunnen in de loop van de tijd veranderen. Lees ze altijd uit de onderstaande responsheaders, niet uit momentopnames in de documentatie.
Responsheaders (responsen waarop rate limiting van toepassing is, inclusief 429):
| Header | Betekenis |
|---|---|
X-RateLimit-Limit | Limiet van de strengste dimensie die op dat moment geldt |
X-RateLimit-Remaining | Kleinste resterende quotum over de drie dimensies |
X-RateLimit-Reset | Unix-tijdstempel (seconden) waarop het huidige venster opnieuw begint |
Bij een 429 bovendien:
| Header | Betekenis |
|---|---|
Retry-After | Aanbevolen wachttijd voor een nieuwe poging (seconden) |
Voorbeeld van een 429-body (de message weerspiegelt de ingestelde limieten op het moment van het verzoek):
{
"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": "..."
}Clientgedrag: lees, wanneer aanwezig, X-RateLimit-Remaining en wacht proactief. Wacht bij een 429 minstens Retry-After seconden (of tot X-RateLimit-Reset) voordat je het opnieuw probeert. Hardcode limietwaarden niet.
Zie Fouten, limieten en nieuwe pogingen voor het volledige beleid voor nieuwe pogingen en richtlijnen voor backoff. Als je hogere rate limits nodig hebt, neem dan contact op met [email protected].
Best practices
1. Ga zorgvuldig met fouten om
Controleer altijd de responsstatus en handel fouten correct af:
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. Implementeer logica voor nieuwe pogingen
Gebruik exponentiële backoff voor tijdelijke fouten (5xx-statuscodes):
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. Cache responsen
Overweeg om responsen voor identieke query's te cachen om het aantal API-aanroepen te beperken en de responstijd te verbeteren.
4. Valideer invoer
Valideer de invoer van de gebruiker voordat je deze naar de API stuurt:
- Zorg dat de query niet leeg is
- Controleer de lengte van de query (1-2000 tekens)
- Schoon de invoer op om injectieaanvallen te voorkomen
5. Houd je gebruik in de gaten
Volg je API-gebruik om binnen de rate limits te blijven en kosten te optimaliseren:
- Log het aantal verzoeken en de responstijden
- Houd foutpercentages in de gaten
- Stel waarschuwingen in voor ongebruikelijke patronen
Support
Hulp nodig bij de Chat API?
- Lees de handleiding Aan de slag
- Raadpleeg de authenticatiedocumentatie
- Neem contact op met [email protected] en vermeld je request-ID
Changelog
v2.0.0 (huidige versie)
- Eerste release van de Chat API
- Ondersteuning voor query's in natuurlijke taal
- Integratie met realtime zoeken op het web
- Door AI gegenereerde antwoorden met bronverwijzingen