Query API
Call Kendr surfaces with cURL, JavaScript, Python, C#, Java, and Go.
Integration rules
| Item | Value |
|---|---|
| Base domain | https://api.kendr.org |
| Public discovery | GET /api/catalog, GET /api/public/models, and GET /api/openapi.json |
| Query execution | POST /api/v1/query; Kendr validates auth and credits, executes the selected surface, then returns a stable Kendr result payload. |
| Primary server auth | Authorization: Bearer kndr_live_... or X-API-Key: kndr_live_... |
| Customer state | GET /api/me/dashboard returns user, packages, api_keys, purchases, ledger, and surfaces |
Auth headers accepted by the query route
| Mode | Header | When to use it |
|---|---|---|
| API key | Authorization: Bearer kndr_live_... | Best for server-to-server integrations and background jobs. |
| API key | X-API-Key: kndr_live_... | Alternative header when bearer auth is not convenient. |
| App session | X-Kendr-Session: SESSION_TOKEN | Best when your app just authenticated the user through Kendr. |
| OAuth bearer | Authorization: Bearer kndr_oat_... | Best for Kendr Desktop or CLI flows using PKCE or device code with the app scope. |
| Browser cookie | kendr_session cookie | Works for browser-origin requests after /api/auth/otp/verify. |
Query request body
| Field | Required | Meaning |
|---|---|---|
| surface | Yes | The Kendr surface key, such as web_search, ai_search, web_answer, google_search, google_maps, google_flights, or google_hotels. |
| query | Yes | The primary query string. |
| params | No | An object for optional values such as gl, hl, page, location, or travel fields. |
| Top-level extras | No | Optional params can also be sent beside surface and query. Kendr merges them with params. |
{
"surface": "google_search",
"query": "best llm observability tools",
"params": {
"gl": "us",
"hl": "en",
"page": 1
}
}
Query examples
Kendr is a plain HTTPS and JSON API. The same request contract works from JavaScript, Python, .NET, Java, and Go, so you can use whichever runtime already exists in your stack.
API key auth
curl https://api.kendr.org/api/v1/query \
-X POST \
-H "Authorization: Bearer $KENDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"surface": "google_search",
"query": "best llm observability tools",
"params": {
"gl": "us",
"hl": "en",
"page": 1
}
}'
App session auth
curl https://api.kendr.org/api/v1/query \
-X POST \
-H "X-Kendr-Session: $KENDR_SESSION" \
-H "Content-Type: application/json" \
-d '{
"surface": "google_maps",
"query": "coworking spaces in austin",
"params": {
"gl": "us",
"hl": "en"
}
}'
Kendr currently ships helper clients for JavaScript and Python. Use the tabs to switch between Curl, JavaScript, Python, .NET, Java, and Go for the same query contract.
Curl request with an API key
curl https://api.kendr.org/api/v1/query \
-X POST \
-H "Authorization: Bearer $KENDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"surface": "google_search",
"query": "best llm observability tools",
"params": {
"gl": "us",
"hl": "en",
"page": 1
}
}'
Server-side fetch request to POST /api/v1/query
const response = await fetch('https://api.kendr.org/api/v1/query', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.KENDR_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
surface: 'google_search',
query: 'best llm observability tools',
params: { gl: 'us', hl: 'en', page: 1 }
})
});
const payload = await response.json();
console.log(payload.data, payload.remaining_credits);
Python requests example against the same endpoint
import os
import requests
response = requests.post(
'https://api.kendr.org/api/v1/query',
headers={
'Authorization': f"Bearer {os.environ['KENDR_API_KEY']}",
'Content-Type': 'application/json',
},
json={
'surface': 'google_search',
'query': 'best llm observability tools',
'params': {'gl': 'us', 'hl': 'en', 'page': 1},
},
timeout=30,
)
payload = response.json()
print(payload['data'])
print(payload['remaining_credits'])
.NET HttpClient example
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("KENDR_API_KEY"));
var body = new
{
surface = "google_search",
query = "best llm observability tools",
@params = new
{
gl = "us",
hl = "en",
page = 1
}
};
using var response = await client.PostAsync(
"https://api.kendr.org/api/v1/query",
new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json")
);
response.EnsureSuccessStatusCode();
using var stream = await response.Content.ReadAsStreamAsync();
var payload = await JsonSerializer.DeserializeAsync(stream);
Console.WriteLine(payload.GetProperty("data").ToString());
Console.WriteLine(payload.GetProperty("remaining_credits").GetInt32());
Java HttpClient example
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
String requestBody = """
{
"surface": "google_search",
"query": "best llm observability tools",
"params": {
"gl": "us",
"hl": "en",
"page": 1
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.kendr.org/api/v1/query"))
.header("Authorization", "Bearer " + System.getenv("KENDR_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Go net/http example
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body := map[string]any{
"surface": "google_search",
"query": "best llm observability tools",
"params": map[string]any{
"gl": "us",
"hl": "en",
"page": 1,
},
}
rawBody, err := json.Marshal(body)
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.kendr.org/api/v1/query", bytes.NewReader(rawBody))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("KENDR_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var payload map[string]any
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload["data"])
fmt.Println(payload["remaining_credits"])
}
Successful response and errors
Successful query response
{
"ok": true,
"surface": "google_search",
"credits_charged": 1,
"remaining_credits": 249,
"data": {
"results": [],
"answer": "",
"citations": []
},
"normalized": {
"results": [],
"answer": "",
"citations": []
}
}
Errors to handle
- 400: invalid payload, missing surface, unsupported surface, or invalid JSON.
- 401: no valid API key, session, or OAuth bearer token was supplied.
- 402: the wallet does not have enough credits for the requested surface.
- 502: the requested surface could not be completed.
Kendr charges credits only after the request succeeds. Failed attempts do not directly consume credits.