Felo API PlatformFelo API Platform

Felo APIs

Chat API

Додайте розмовний пошук AI з аналізом запитів, вебджерелами та цитатами.

POST/v2/chat

Автентифікація

Bearer API key

Тип вмісту

application/json

Примітки щодо обмежень

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

Chat API дає змогу інтегрувати розмовний пошук на основі ШІ у ваші застосунки. Надішліть запит природною мовою та отримайте розумну відповідь, згенеровану з результатів вебпошуку в реальному часі.

Про обмеження швидкості, відповіді з помилками та поведінку повторних спроб див. Помилки, обмеження та повторні спроби.

Огляд

Chat API виконує такі операції:

  1. Аналізує та оптимізує ваш запит
  2. Шукає у вебі релевантну інформацію
  3. Ранжує та фільтрує результати пошуку
  4. Генерує ґрунтовну відповідь ШІ на основі джерел
  5. Повертає відповідь разом із цитуванням джерел

Варіанти використання:

  • Розмовні помічники ШІ
  • Інструменти досліджень та пошуку інформації
  • Чатботи підтримки клієнтів із вебзнаннями
  • Освітні застосунки
  • Інструменти створення вмісту

Автентифікація

Усі запити до Chat API потребують автентифікації за допомогою API-ключа. Додайте свій API-ключ у заголовок Authorization:

Authorization: Bearer YOUR_API_KEY

Докладніше про отримання та використання API-ключа див. у посібнику з автентифікації.

Використання з агентами ШІ

Установіть повний пакет felo-ai, коли хочете, щоб агент використовував Search та кожен інший доступний Felo Skill. Інсталятор динамічно знаходить кожен каталог пакета, що містить SKILL.md, тому він включає майбутні Skills, а не фіксований підмножину. Установіть їх у рідний каталог для вашого агента: Codex використовує ~/.codex/skills, Claude Code — ~/.claude/skills, OpenClaw — ~/.agents/skills, а Hermes Agent — ~/.hermes/skills. Кроки безпечного зв'язування, налаштування API-ключа та перевірки для кожної платформи див. у посібнику з ручного налаштування агента ШІ.

Endpoint

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

Запит

Заголовки

ЗаголовокОбов'язковийОпис
AuthorizationТакВаш API-ключ у форматі: Bearer YOUR_API_KEY
Content-TypeТакМає бути application/json

Параметри тіла

ПараметрТипОбов'язковийОписОбмеження
querystringТакЗапитання користувача або пошуковий запит1-2000 символів

Приклад запиту

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

Відповідь

Успішна відповідь (200 OK)

Коли запит успішний, API повертає відповідь JSON із такою структурою:

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

Поля відповіді

ПолеТипОпис
statusstring | numberСтатус відповіді: "ok" у разі успіху; відповіді з помилками використовують код стану HTTP як число
messagestring | nullДодаткове повідомлення (null для успішних запитів)
dataobjectДані відповіді (присутні лише коли статус "ok")
data.idstringУнікальний ідентифікатор цього сеансу чату
data.message_idstringУнікальний ідентифікатор цього конкретного повідомлення
data.answerstringВідповідь, згенерована ШІ на запит
data.query_analysisobjectАналіз запиту користувача
data.query_analysis.queriesstring[]Оптимізовані пошукові запити, отримані з вхідних даних користувача
data.resourcesarrayСписок вебджерел, використаних для генерації відповіді
data.resources[].linkstringURL-адреса джерела
data.resources[].titlestringЗаголовок сторінки джерела
data.resources[].snippetstringРелевантний уривок із джерела

Відповідь з помилкою

Коли виникає помилка, API повертає спільну структуру помилки:

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

Поля відповіді з помилкою

ПолеТипОпис
statusnumberКод стану HTTP; успішні відповіді використовують "ok"
codestringКод помилки, що ідентифікує тип помилки
messagestringОпис помилки для людини
request_idstringУнікальний ідентифікатор цього запиту (корисний для підтримки)

Коди помилок

HTTPКодЗначення
400Код перевірки endpointПоле query відсутнє, порожнє або задовге; прочитайте message, щоб дізнатися конкретну проблему
401UNAUTHORIZEDAPI-ключ відсутній, недійсний або відкликаний
429RATE_LIMITEDПеревищено обмеження швидкості
502CHAT_FAILEDВнутрішня помилка сервісу
503SERVICE_UNAVAILABLEСервіс тимчасово недоступний

Спільну структуру, інші коди помилок і правила повторних спроб див. у Помилки, обмеження та повторні спроби.

Приклади

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

Відповідь:

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

Обмеження швидкості

Користувачі з чинною платною підпискою Felo (зокрема корпоративною) звільнені від усіх обмежень швидкості /v2/chat як для автентифікації за API-ключем, так і для OAuth. Звільнені відповіді не містять заголовків X-RateLimit-*.

Користувачі без платної підписки підпадають під обмеження швидкості за трьома вимірами. Якщо статус підписки неможливо перевірити, ці обмеження все одно застосовуються:

  • Для кожного API-ключа — обмежує запити, зроблені з одним API-ключем, у вікні 1 хвилина.
  • Для кожного користувача (хвилина) — обмежує сукупні запити за всіма API-ключами, якими володіє користувач, у вікні 1 хвилина.
  • Для кожного користувача (година) — обмежує сукупні запити за всіма API-ключами, якими володіє користувач, у вікні 1 година.

Перевищення будь-якого виміру спричиняє відповідь 429 Too Many Requests.

Точні числові ліміти можуть змінюватися з часом. Завжди читайте їх із наведених нижче заголовків відповіді, а не із знімків документації.

Заголовки відповіді (відповіді, що підпадають під обмеження швидкості, зокрема 429):

ЗаголовокЗначення
X-RateLimit-LimitЛіміт найжорсткішого виміру, що наразі діє
X-RateLimit-RemainingМінімальна залишкова квота за трьома вимірами
X-RateLimit-ResetЧасова позначка Unix (секунди), коли скидається поточне вікно

Для 429 додатково:

ЗаголовокЗначення
Retry-AfterРекомендована затримка повторної спроби (секунди)

Приклад тіла 429 (message відображає поточні налаштовані ліміти на момент запиту):

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

Поведінка клієнта: коли він присутній, читайте X-RateLimit-Remaining і завчасно збільшуйте інтервал. Для 429 зачекайте щонайменше Retry-After секунд (або до X-RateLimit-Reset), перш ніж повторити спробу. Не вшивайте значення лімітів жорстко.

Повну політику повторних спроб і рекомендації щодо збільшення інтервалу див. у Помилки, обмеження та повторні спроби. Якщо вам потрібні вищі обмеження швидкості, зверніться до [email protected].

Рекомендації

1. Коректно обробляйте помилки

Завжди перевіряйте статус відповіді та належним чином обробляйте помилки:

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. Реалізуйте логіку повторних спроб

Для тимчасових помилок (коди стану 5xx) реалізуйте експоненційне збільшення інтервалу:

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. Кешуйте відповіді

Розгляньте кешування відповідей на ідентичні запити, щоб зменшити кількість викликів API та скоротити час відповіді.

4. Перевіряйте вхідні дані

Перевіряйте вхідні дані користувача, перш ніж надсилати їх до API:

  • Переконайтеся, що запит не порожній
  • Перевірте довжину запиту (1-2000 символів)
  • Очищуйте вхідні дані, щоб запобігти атакам ін'єкції

5. Відстежуйте використання

Відстежуйте використання API, щоб дотримуватися обмежень швидкості та оптимізувати витрати:

  • Записуйте в журнал кількість запитів і час відповіді
  • Відстежуйте частоту помилок
  • Налаштуйте сповіщення про нетипові шаблони

Підтримка

Потрібна допомога з Chat API?

Журнал змін

v2.0.0 (поточна)

  • Початковий випуск Chat API
  • Підтримка запитів природною мовою
  • Інтеграція вебпошуку в реальному часі
  • Відповіді, згенеровані ШІ, з цитуванням джерел