Felo API PlatformFelo API Platform

Felo APIs

Chat API

Integrasikan pencarian percakapan berbasis AI dengan analisis kueri, sumber web, dan kutipan.

POST/v2/chat

Autentikasi

Bearer API key

Tipe konten

application/json

Catatan batas laju

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

Chat API memungkinkan Anda mengintegrasikan pencarian percakapan berbasis AI ke dalam aplikasi Anda. Kirim kueri dalam bahasa alami dan terima jawaban cerdas yang dihasilkan dari hasil pencarian web waktu nyata.

Untuk batas laju, respons error, dan perilaku percobaan ulang, lihat Error, Batas, dan Percobaan Ulang.

Ringkasan

Chat API melakukan operasi berikut:

  1. Menganalisis dan mengoptimalkan kueri Anda
  2. Mencari informasi yang relevan di web
  3. Memeringkat dan memfilter hasil pencarian
  4. Menghasilkan jawaban AI yang komprehensif berdasarkan sumber
  5. Mengembalikan jawaban beserta kutipan sumber

Kasus Penggunaan:

  • Asisten AI percakapan
  • Alat riset dan pengambilan informasi
  • Chatbot dukungan pelanggan dengan pengetahuan web
  • Aplikasi pendidikan
  • Alat pembuatan konten

Autentikasi

Semua permintaan ke Chat API memerlukan autentikasi menggunakan kunci API. Sertakan kunci API Anda di header Authorization:

Authorization: Bearer YOUR_API_KEY

Lihat Panduan Autentikasi untuk detail tentang cara memperoleh dan menggunakan kunci API Anda.

Penggunaan dengan Agen AI

Instal paket felo-ai lengkap jika Anda ingin Agen menggunakan Search dan setiap Felo Skill lain yang tersedia. Penginstal secara dinamis menemukan setiap direktori paket yang berisi SKILL.md, sehingga mencakup Skill mendatang, bukan sebagian tetap. Instal semuanya di direktori asli Agen Anda: Codex menggunakan ~/.codex/skills, Claude Code menggunakan ~/.claude/skills, OpenClaw menggunakan ~/.agents/skills, dan Hermes Agent menggunakan ~/.hermes/skills. Lihat panduan penyiapan Agen AI manual untuk langkah tautan aman, kunci API, dan verifikasi bagi setiap platform.

Endpoint

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

Permintaan

HeaderWajibDeskripsi
AuthorizationYaKunci API Anda dalam format: Bearer YOUR_API_KEY
Content-TypeYaHarus application/json

Parameter Isi Permintaan

ParameterTipeWajibDeskripsiBatasan
querystringYaPertanyaan atau kueri pencarian pengguna1-2000 karakter

Contoh Permintaan

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

Respons

Respons Berhasil (200 OK)

Saat permintaan berhasil, API mengembalikan respons JSON dengan struktur berikut:

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

Field Respons

FieldTipeDeskripsi
statusstring | numberStatus respons: "ok" saat berhasil; respons error menggunakan kode status HTTP sebagai angka
messagestring | nullPesan tambahan (null untuk permintaan yang berhasil)
dataobjectData respons (hanya ada saat status bernilai "ok")
data.idstringPengenal unik untuk sesi chat ini
data.message_idstringPengenal unik untuk pesan tertentu ini
data.answerstringJawaban yang dihasilkan AI untuk kueri
data.query_analysisobjectAnalisis kueri pengguna
data.query_analysis.queriesstring[]Kueri pencarian yang dioptimalkan dari masukan pengguna
data.resourcesarrayDaftar sumber web yang digunakan untuk menghasilkan jawaban
data.resources[].linkstringURL sumber
data.resources[].titlestringJudul halaman sumber
data.resources[].snippetstringKutipan relevan dari sumber

Respons Error

Saat terjadi error, API mengembalikan envelope error bersama:

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

Field Respons Error

FieldTipeDeskripsi
statusnumberKode status HTTP; respons berhasil menggunakan "ok"
codestringKode error yang mengidentifikasi jenis error
messagestringDeskripsi error yang dapat dibaca manusia
request_idstringPengenal unik untuk permintaan ini (berguna untuk dukungan)

Kode Error

HTTPKodeArti
400Kode validasi endpointField query tidak ada, kosong, atau terlalu panjang; baca message untuk masalah spesifiknya
401UNAUTHORIZEDKunci API tidak ada, tidak valid, atau dicabut
429RATE_LIMITEDBatas laju terlampaui
502CHAT_FAILEDError layanan internal
503SERVICE_UNAVAILABLELayanan sementara tidak tersedia

Untuk envelope bersama, kode error lain, dan aturan percobaan ulang, lihat Error, Batas, dan Percobaan Ulang.

Contoh

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

Batas Laju

Pengguna dengan langganan Felo berbayar yang efektif (termasuk langganan perusahaan) dibebaskan dari semua batas laju /v2/chat, baik untuk autentikasi kunci API maupun OAuth. Respons yang dibebaskan tidak menyertakan header X-RateLimit-*.

Pengguna tanpa langganan berbayar tunduk pada batas laju dalam tiga dimensi. Jika status langganan tidak dapat diverifikasi, batas ini tetap berlaku:

  • Per Kunci API - membatasi permintaan yang dibuat dengan satu kunci API dalam jendela 1 menit.
  • Per Pengguna (menit) - membatasi total permintaan di semua kunci API milik pengguna dalam jendela 1 menit.
  • Per Pengguna (jam) - membatasi total permintaan di semua kunci API milik pengguna dalam jendela 1 jam.

Terlampauinya dimensi mana pun memicu respons 429 Too Many Requests.

Batas numerik yang tepat dapat berubah seiring waktu. Selalu baca dari header respons di bawah ini, bukan dari snapshot dokumentasi.

Header respons (respons yang tunduk pada pembatasan laju, termasuk 429):

HeaderArti
X-RateLimit-LimitBatas dari dimensi paling ketat yang sedang berlaku
X-RateLimit-RemainingSisa kuota minimum di ketiga dimensi
X-RateLimit-ResetStempel waktu Unix (detik) saat jendela saat ini diatur ulang

Pada 429, tambahan:

HeaderArti
Retry-AfterPenundaan percobaan ulang yang disarankan (detik)

Contoh isi 429 (message mencerminkan batas yang dikonfigurasi saat permintaan):

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

Perilaku klien: jika ada, baca X-RateLimit-Remaining dan mundur secara proaktif. Saat 429, tunggu setidaknya Retry-After detik (atau hingga X-RateLimit-Reset) sebelum mencoba lagi. Jangan menuliskan nilai batas secara hardcode.

Untuk kebijakan percobaan ulang lengkap dan panduan backoff, lihat Error, Batas, dan Percobaan Ulang. Jika Anda memerlukan batas laju yang lebih tinggi, hubungi [email protected].

Praktik Terbaik

1. Tangani Error dengan Baik

Selalu periksa status respons dan tangani error dengan tepat:

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. Terapkan Logika Percobaan Ulang

Untuk error sementara (kode status 5xx), terapkan backoff eksponensial:

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. Gunakan Cache untuk Respons

Pertimbangkan untuk menyimpan respons di cache untuk kueri yang identik guna mengurangi panggilan API dan meningkatkan waktu respons.

4. Validasi Masukan

Validasi masukan pengguna sebelum mengirim ke API:

  • Pastikan kueri tidak kosong
  • Periksa panjang kueri (1-2000 karakter)
  • Sanitasi masukan untuk mencegah serangan injeksi

5. Pantau Penggunaan

Lacak penggunaan API Anda agar tetap dalam batas laju dan mengoptimalkan biaya:

  • Catat jumlah permintaan dan waktu respons
  • Pantau tingkat error
  • Siapkan peringatan untuk pola yang tidak biasa

Dukungan

Butuh bantuan dengan Chat API?

Riwayat Perubahan

v2.0.0 (Saat Ini)

  • Rilis awal Chat API
  • Dukungan untuk kueri bahasa alami
  • Integrasi pencarian web waktu nyata
  • Jawaban yang dihasilkan AI dengan kutipan sumber